{"version":3,"sources":["jsdelivr-header.js","/npm/@browserai/browserai@2.0.4/src/index.ts","/npm/@browserai/browserai@2.0.4/src/engines/mlc-engine-wrapper.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/env.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/generic.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/core.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/hub.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/maths.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/backends/onnx.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/ops/registry.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/tensor.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/data-structures.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/tokenizers.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/whisper/common_whisper.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/configs.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/image.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/devices.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/dtypes.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/constants.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/generation/logits_process.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/generation/configuration_utils.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/generation/stopping_criteria.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/generation/logits_sampler.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/whisper/generation_whisper.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/base/processing_utils.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/processors.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/base/image_processors_utils.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/janus/image_processing_janus.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/auto/image_processing_auto.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/florence2/processing_florence2.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/idefics3/processing_idefics3.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/mgp_str/processing_mgp_str.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/feature_extractors.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/base/feature_extraction_utils.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/audio.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/audio_spectrogram_transformer/feature_extraction_audio_spectrogram_transformer.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/clap/feature_extraction_clap.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/moonshine/feature_extraction_moonshine.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/pyannote/feature_extraction_pyannote.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/seamless_m4t/feature_extraction_seamless_m4t.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/speecht5/feature_extraction_speecht5.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/wav2vec2/feature_extraction_wav2vec2.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/wespeaker/feature_extraction_wespeaker.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/whisper/feature_extraction_whisper.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/auto/feature_extraction_auto.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/moonshine/processing_moonshine.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/janus/processing_janus.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/jina_clip/processing_jina_clip.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/phi3_v/processing_phi3_v.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/paligemma/processing_paligemma.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/pyannote/processing_pyannote.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/qwen2_vl/processing_qwen2_vl.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/sam/processing_sam.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/speecht5/processing_speecht5.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/wav2vec2/processing_wav2vec2.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/whisper/processing_whisper.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/image_processors.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/bit/image_processing_bit.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/chinese_clip/image_processing_chinese_clip.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/clip/image_processing_clip.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/convnext/image_processing_convnext.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/deit/image_processing_deit.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/idefics3/image_processing_idefics3.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/jina_clip/image_processing_jina_clip.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/llava_onevision/image_processing_llava_onevision.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/phi3_v/image_processing_phi3_v.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/qwen2_vl/image_processing_qwen2_vl.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/sam/image_processing_sam.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/siglip/image_processing_siglip.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/swin2sr/image_processing_swin2sr.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/vitmatte/image_processing_vitmatte.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/vitpose/image_processing_vitpose.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/models/auto/processing_auto.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/pipelines.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/generation/streamers.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/phonemize.ts","/npm/@browserai/browserai@2.0.4/src/libs/transformers/utils/voices.ts","/npm/@browserai/browserai@2.0.4/src/engines/tts-engine.ts","/npm/@browserai/browserai@2.0.4/src/engines/transformer-engine-wrapper.ts","/npm/@browserai/browserai@2.0.4/src/config/models/mlc-models.json","/npm/@browserai/browserai@2.0.4/src/config/models/transformers-models.json","/npm/@browserai/browserai@2.0.4/src/core/llm/index.ts","/npm/@browserai/browserai@2.0.4/src/core/database/implementation/indexeddb.ts","/npm/@browserai/browserai@2.0.4/src/core/database/implementation/sqlite.ts","/npm/@browserai/browserai@2.0.4/src/core/database/index.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/html-cleaner.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/content-identifier.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/types.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/browser-agent.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/dom-analyzer.ts","/npm/@browserai/browserai@2.0.4/src/core/agent/browser-actions.ts","/npm/@browserai/browserai@2.0.4/src/core/parsers/pdf.ts","/npm/@browserai/browserai@2.0.4/src/core/parsers/csv.ts","/npm/@browserai/browserai@2.0.4/src/core/parsers/docx.ts","/npm/@browserai/browserai@2.0.4/src/core/parsers/image.ts"],"names":[],"mappings":"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CL,IAAK,IACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IAGL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,KACL,IAAK,KACL,IAAK,IACL,IAAK,KACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,GAGL,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,KACN,KAAM,KAcF,oBAAiD,CAErD,EAAK,IACL,IAAK,KACL,EAAK,IACL,IAAK,KACL,EAAK,IACL,IAAK,KACL,EAAK,IACL,IAAK,KACL,EAAK,IACL,IAAK,KACL,IAAK,IAGL,EAAK,IACL,EAAK,IACL,EAAK,IACL,GAAM,KACN,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,GACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,GAAM,IACN,EAAK,IACL,EAAK,IACL,IAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,GAAM,IACN,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,KACL,EAAK,IACL,EAAK,KAiDD,qBAAkD,CAEtD,EAAK,IACL,GAAM,KACN,EAAK,IACL,GAAM,KACN,EAAK,IACL,GAAM,KACN,EAAK,KACL,GAAM,KACN,EAAK,KACL,GAAM,KAGN,GAAM,KACN,GAAM,KACN,GAAM,KACN,GAAM,MACN,GAAM,MACN,GAAM,MACN,GAAM,KACN,GAAM,KACN,GAAM,IACN,GAAM,IACN,GAAM,IACN,GAAM,IACN,IAAO,KACP,IAAO,KAGP,EAAK,IACL,EAAK,KACL,EAAK,KACL,EAAK,KACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,EAAK,IACL,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","file":"/npm/@browserai/browserai@2.0.4/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@browserai/browserai@2.0.4/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","// Import BrowserAI first\nimport { BrowserAI } from './core/llm';\n\n// Export everything as named exports\nexport { BrowserAI };\nexport { MLCEngineWrapper } from './engines/mlc-engine-wrapper';\nexport { TransformersEngineWrapper } from './engines/transformer-engine-wrapper';\nexport { default as mlcModels } from './config/models/mlc-models.json';\nexport { default as transformersModels } from './config/models/transformers-models.json';\n\nexport { DatabaseImpl } from './core/database';\nexport * from './core/agent';\n\n// Export PDF parser\nexport { \n  PDFParser, \n  extractTextFromPdf, \n  extractStructuredTextFromPdf,\n  processPdfFile,\n  pdfToText,\n  type PDFParseOptions,\n  type PDFParseResult\n} from './core/parsers/pdf';\n\n// Export CSV parser\nexport {\n  CSVParser,\n  extractDataFromCSV,\n  extractTextFromCSV,\n  processCSVFile,\n  csvToText,\n  type CSVParseOptions,\n  type CSVParseResult\n} from './core/parsers/csv';\n\n// Export DOCX parser\nexport {\n  DOCXParser,\n  extractTextFromDOCX,\n  processDOCXFile,\n  docxToText,\n  type DOCXParseOptions,\n  type DOCXParseResult\n} from './core/parsers/docx';\n\n// Export image parser\nexport {\n  ImageParser,\n  extractTextFromImage,\n  processImageFile,\n  imageToText\n} from './core/parsers/image';\nexport type { ImageParseOptions, ImageParseResult } from './core/parsers/image';\n","// src/engines/mlc-engine-wrapper.ts\nimport { \n  CreateMLCEngine, \n  MLCEngineInterface, \n  AppConfig, \n  modelLibURLPrefix, \n  modelVersion, \n  prebuiltAppConfig,\n  CreateWebWorkerMLCEngine\n} from '@mlc-ai/web-llm';\nimport { ModelConfig } from '../config/models/types';\n\n// Add this worker code as a string at the top of the file\nconst workerCode = `\n  // Ensure we're in a worker context\n  if (typeof self === 'undefined') {\n    throw new Error('This script must be run in a Web Worker');\n  }\n\n  console.log('[Worker] Starting initialization...');\n\n  // Wrap the entire worker code in a try-catch\n  try {\n    // Wait for the main thread to send us the module URL\n    self.onmessage = async (msg) => {\n      if (msg.data.type === 'init') {\n        console.log('[Worker] Received init message');\n        const moduleURL = msg.data.moduleURL;\n        \n        try {\n          const module = await import(moduleURL);\n          console.log('[Worker] Module loaded successfully');\n          const handler = new module.WebWorkerMLCEngineHandler();\n          \n          // Replace onmessage handler with the actual handler\n          self.onmessage = (msg) => {\n            console.log('[Worker] Received message:', msg.data);\n            try {\n              handler.onmessage(msg);\n            } catch (error) {\n              console.error('[Worker] Handler error:', error);\n              self.postMessage({\n                type: 'error',\n                error: error instanceof Error ? error.message : String(error)\n              });\n            }\n          };\n          \n          self.postMessage({ type: 'ready' });\n          console.log('[Worker] Handler initialized successfully');\n        } catch (error) {\n          console.error('[Worker] Failed to load module:', error);\n          self.postMessage({\n            type: 'error',\n            error: 'Failed to initialize worker: ' + (error instanceof Error ? error.message : String(error))\n          });\n        }\n      }\n    };\n  } catch (error) {\n    console.error('[Worker] Initialization error:', error);\n    self.postMessage({\n      type: 'error',\n      error: 'Worker initialization failed: ' + (error instanceof Error ? error.message : String(error))\n    });\n  }\n\n  self.onerror = (error) => {\n    console.error('[Worker] Global error:', error);\n    self.postMessage({\n      type: 'error',\n      error: error instanceof ErrorEvent ? error.message : 'Unknown worker error'\n    });\n  };\n\n  self.onmessageerror = (error) => {\n    console.error('[Worker] Message error:', error);\n    self.postMessage({\n      type: 'error',\n      error: 'Message error: ' + (error instanceof Error ? error.message : String(error))\n    });\n  };\n\n  console.log('[Worker] Basic initialization complete');\n`;\n\ninterface MLCLoadModelOptions {\n  useWorker?: boolean;\n  onProgress?: (progress: any) => void;\n  quantization?: string;\n  [key: string]: any;\n}\n\n// Add a helper class to manage the model cache with LRU strategy\nclass MLCModelCacheManager {\n  private static instance: MLCModelCacheManager;\n  private modelQueue: string[] = [];\n  private modelSizes: Map<string, number> = new Map(); // Track size of each model\n  private maxCacheSize = 1024 * 1024 * 1024; // 1GB max cache size (adjust as needed)\n  private readonly cacheThreshold = 0.8; // 80% threshold for cleanup\n  private currentCacheSize = 0;\n\n  private constructor() {\n    // Calculate the current cache size\n    this.calculateCacheSizeAsync();\n    \n    // Also estimate available storage and adjust max cache size\n    this.estimateAvailableStorageAndSetLimit();\n  }\n\n  public static getInstance(): MLCModelCacheManager {\n    if (!MLCModelCacheManager.instance) {\n      MLCModelCacheManager.instance = new MLCModelCacheManager();\n    }\n    return MLCModelCacheManager.instance;\n  }\n\n  // Scan all caches to calculate total size\n  private async calculateCacheSizeAsync(): Promise<void> {\n    try {\n      const cacheNames = ['webllm/config', 'webllm/wasm', 'webllm/model'];\n      this.currentCacheSize = 0;\n      this.modelSizes.clear();\n      \n      // Map to collect all URLs by model ID for debugging\n      const modelUrlMap: Map<string, string[]> = new Map();\n      \n      // Map to track original model IDs to normalized ones\n      const normalizedModelMap: Map<string, string> = new Map();\n      \n      console.log('Beginning cache calculation...');\n      \n      for (const cacheName of cacheNames) {\n        console.log(`Scanning cache: ${cacheName}`);\n        const cache = await caches.open(cacheName);\n        const keys = await cache.keys();\n        \n        console.log(`Found ${keys.length} entries in ${cacheName}`);\n        \n        for (const key of keys) {\n          const response = await cache.match(key);\n          if (!response) continue;\n          \n          const blob = await response.blob();\n          const size = blob.size;\n          this.currentCacheSize += size;\n          \n          // Try to determine which model this entry belongs to\n          const url = key.url;\n          \n          // Extract the raw model ID from the URL\n          let rawModelId = this.extractRawModelId(url);\n          \n          if (rawModelId) {\n            // Normalize the model ID to avoid duplicates\n            let normalizedModelId = this.normalizeModelId(rawModelId);\n            \n            // Track the normalization for debugging\n            if (!normalizedModelMap.has(rawModelId)) {\n              normalizedModelMap.set(rawModelId, normalizedModelId);\n            }\n            \n            // Track URLs for debugging\n            if (!modelUrlMap.has(normalizedModelId)) {\n              modelUrlMap.set(normalizedModelId, []);\n            }\n            modelUrlMap.get(normalizedModelId)?.push(url);\n            \n            if (!this.modelSizes.has(normalizedModelId)) {\n              this.modelSizes.set(normalizedModelId, 0);\n              if (!this.modelQueue.includes(normalizedModelId)) {\n                this.modelQueue.push(normalizedModelId);\n              }\n            }\n            this.modelSizes.set(normalizedModelId, (this.modelSizes.get(normalizedModelId) || 0) + size);\n          } else {\n            console.log(`Couldn't determine model for URL: ${url}`);\n          }\n        }\n      }\n      \n      // Print detailed debug info\n      console.log('--- MODEL CACHE DEBUG INFO ---');\n      console.log(`Total cache size: ${this.formatBytes(this.currentCacheSize)}`);\n      console.log(`Models in modelQueue: ${this.modelQueue.length}`);\n      console.log(`Models in modelSizes map: ${this.modelSizes.size}`);\n      \n      // Normalize the model queue to ensure consistency\n      this.normalizeModelQueue();\n      \n      console.log('Raw to normalized model mapping:');\n      for (const [raw, normalized] of normalizedModelMap.entries()) {\n        console.log(`- ${raw} → ${normalized}`);\n      }\n      \n      console.log('Detected models:');\n      for (const [modelId, size] of this.modelSizes.entries()) {\n        console.log(`- ${modelId}: ${this.formatBytes(size)} (${modelUrlMap.get(modelId)?.length || 0} files)`);\n      }\n      \n      console.log('LRU Queue order (oldest to newest):');\n      this.modelQueue.forEach((id, index) => {\n        console.log(`${index + 1}. ${id}`);\n      });\n      \n      console.log(`Cache calculated. Total size: ${this.formatBytes(this.currentCacheSize)}, Models: ${this.modelQueue.length}`);\n    } catch (error) {\n      console.error('Error calculating cache size:', error);\n    }\n  }\n  \n  // Extract raw model ID from URL using patterns based on the model config\n  private extractRawModelId(url: string): string | null {\n    // Special cases for specific model families to maintain version numbers\n    \n    // Llama models (llama-3.2-1b-instruct, llama-3.2-3b-instruct)\n    const llamaPattern = /\\/(Llama-3\\.2-\\d+[Bb]-Instruct)/i;\n    const llamaMatch = url.match(llamaPattern);\n    if (llamaMatch && llamaMatch[1]) {\n      return llamaMatch[1];\n    }\n    \n    // Hermes models (hermes-llama-3.2-3b)\n    const hermesPattern = /\\/(Hermes-\\d+-Llama-\\d+\\.\\d+-\\d+[Bb])/i;\n    const hermesMatch = url.match(hermesPattern);\n    if (hermesMatch && hermesMatch[1]) {\n      return hermesMatch[1];\n    }\n    \n    // Qwen models (qwen2.5-0.5b-instruct, qwen2.5-1.5b-instruct, qwen2.5-3b-instruct)\n    const qwenPattern = /\\/(Qwen2(?:\\.5)?-\\d+\\.?\\d*[Bb]-Instruct)/i;\n    const qwenMatch = url.match(qwenPattern);\n    if (qwenMatch && qwenMatch[1]) {\n      return qwenMatch[1];\n    }\n    \n    // SmolLM models (smollm2-135m-instruct, smollm2-360m-instruct, smollm2-1.7b-instruct)\n    const smolLMPattern = /\\/(SmolLM2-\\d+\\.?\\d*[BbMG]-Instruct)/i;\n    const smolLMMatch = url.match(smolLMPattern);\n    if (smolLMMatch && smolLMMatch[1]) {\n      return smolLMMatch[1];\n    }\n    \n    // Gemma models (gemma-2b-it)\n    const gemmaPattern = /\\/(gemma-\\d+[Bb]-it)/i;\n    const gemmaMatch = url.match(gemmaPattern);\n    if (gemmaMatch && gemmaMatch[1]) {\n      return gemmaMatch[1];\n    }\n    \n    // TinyLlama models (tinyllama-1.1b-chat-v0.4)\n    const tinyLlamaPattern = /\\/(TinyLlama-\\d+\\.?\\d*[Bb]-Chat-v[\\d\\.]+)/i;\n    const tinyLlamaMatch = url.match(tinyLlamaPattern);\n    if (tinyLlamaMatch && tinyLlamaMatch[1]) {\n      return tinyLlamaMatch[1];\n    }\n    \n    // Phi models (phi-3.5-mini-instruct)\n    const phiPattern = /\\/(Phi-\\d+\\.?\\d+-\\w+-\\w+)/i;\n    const phiMatch = url.match(phiPattern);\n    if (phiMatch && phiMatch[1]) {\n      return phiMatch[1];\n    }\n    \n    // DeepSeek models (deepseek-r1-distill-qwen-1.5b, deepseek-r1-distill-qwen-7b, deepseek-r1-distill-llama-8b)\n    const deepSeekPattern = /\\/(DeepSeek-R1-Distill-(?:Qwen|Llama)-\\d+\\.?\\d*[Bb])/i;\n    const deepSeekMatch = url.match(deepSeekPattern);\n    if (deepSeekMatch && deepSeekMatch[1]) {\n      return deepSeekMatch[1];\n    }\n    \n    // Snowflake arctic embed models (snowflake-arctic-embed-m-b4, snowflake-arctic-embed-s-b4, etc.)\n    const snowflakePattern = /\\/(snowflake-arctic-embed-[ms])(?:-b\\d+)?/i;\n    const snowflakeMatch = url.match(snowflakePattern);\n    if (snowflakeMatch && snowflakeMatch[1]) {\n      return snowflakeMatch[1];\n    }\n    \n    // Fallback for models with quantization and MLC suffix\n    const mlcPattern = /\\/([A-Za-z0-9\\.\\-]+(?:-\\d+\\.?\\d*[BbMG])(?:-[A-Za-z0-9\\.\\-]+)?)-[qQ]\\d[fF]\\d+(?:_\\d+)?-MLC/;\n    const mlcMatch = url.match(mlcPattern);\n    if (mlcMatch && mlcMatch[1]) {\n      return mlcMatch[1];\n    }\n    \n    // Fallback for models with just quantization\n    const quantPattern = /\\/([A-Za-z0-9\\.\\-]+(?:-\\d+\\.?\\d*[BbMG])(?:-[A-Za-z0-9\\.\\-]+)?)-[qQ]\\d[fF]\\d+(?:_\\d+)?/;\n    const quantMatch = url.match(quantPattern);\n    if (quantMatch && quantMatch[1]) {\n      return quantMatch[1];\n    }\n    \n    // Fallback for any other model pattern\n    const genericPattern = /\\/([A-Za-z0-9\\.\\-]+(?:-\\d+\\.?\\d*[BbMG])(?:-[A-Za-z0-9\\.\\-]+)?)/;\n    const genericMatch = url.match(genericPattern);\n    if (genericMatch && genericMatch[1]) {\n      return genericMatch[1];\n    }\n    \n    return null;\n  }\n\n  // Normalize model ID while preserving all important version information\n  private normalizeModelId(rawModelId: string): string {\n    // First, make case-insensitive\n    const lowerCaseId = rawModelId.toLowerCase();\n    \n    // Handle specific model families\n    \n    // Llama models\n    if (lowerCaseId.includes('llama-3.2') && lowerCaseId.includes('instruct')) {\n      const match = rawModelId.match(/(Llama-3\\.2-\\d+[Bb])-Instruct/i);\n      if (match) return match[1] + '-Instruct';\n    }\n    \n    // Hermes models\n    if (lowerCaseId.includes('hermes') && lowerCaseId.includes('llama')) {\n      const match = rawModelId.match(/(Hermes-\\d+-Llama-\\d+\\.\\d+-\\d+[Bb])/i);\n      if (match) return match[1];\n    }\n    \n    // Qwen models - CRUCIAL to maintain version differences\n    if (lowerCaseId.includes('qwen')) {\n      // Preserve the full Qwen version\n      if (lowerCaseId.includes('qwen2.5')) {\n        const match = rawModelId.match(/(Qwen2\\.5-\\d+\\.?\\d*[Bb])-Instruct/i);\n        if (match) return match[1] + '-Instruct';\n      } else if (lowerCaseId.includes('qwen2')) {\n        const match = rawModelId.match(/(Qwen2-\\d+\\.?\\d*[Bb])-Instruct/i);\n        if (match) return match[1] + '-Instruct';\n      }\n    }\n    \n    // SmolLM models\n    if (lowerCaseId.includes('smollm')) {\n      const match = rawModelId.match(/(SmolLM2-\\d+\\.?\\d*[BbMG])(-Instruct)?/i);\n      if (match) return match[1] + (match[2] || '');\n    }\n    \n    // Gemma models\n    if (lowerCaseId.includes('gemma')) {\n      const match = rawModelId.match(/(gemma-\\d+[Bb])-it/i);\n      if (match) return match[1] + '-it';\n    }\n    \n    // TinyLlama models\n    if (lowerCaseId.includes('tinyllama')) {\n      const match = rawModelId.match(/(TinyLlama-\\d+\\.?\\d*[Bb]-Chat-v[\\d\\.]+)/i);\n      if (match) return match[1];\n    }\n    \n    // Phi models\n    if (lowerCaseId.includes('phi')) {\n      const match = rawModelId.match(/(Phi-\\d+\\.?\\d+-\\w+-\\w+)/i);\n      if (match) return match[1];\n    }\n    \n    // DeepSeek models\n    if (lowerCaseId.includes('deepseek')) {\n      const match = rawModelId.match(/(DeepSeek-R1-Distill-(?:Qwen|Llama)-\\d+\\.?\\d*[Bb])/i);\n      if (match) return match[1];\n    }\n    \n    // Snowflake models - keep base model but remove batch size\n    if (lowerCaseId.includes('snowflake')) {\n      const match = rawModelId.match(/(snowflake-arctic-embed-[ms])/i);\n      if (match) return match[1];\n    }\n    \n    // Generic fallback: remove quantization and other suffixes\n    let normalizedId = rawModelId\n      .replace(/-q\\d+f\\d+(_\\d+)?(-MLC)?$/i, '')  // Remove quantization\n      .replace(/-MLC$/i, '');                    // Remove MLC suffix\n    \n    // Remove batch size suffixes\n    normalizedId = normalizedId.replace(/-b\\d+$/i, '');\n    \n    return normalizedId;\n  }\n\n  // Format bytes to human-readable format\n  private formatBytes(bytes: number): string {\n    if (bytes === 0) return '0 Bytes';\n    const k = 1024;\n    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n  }\n\n  // Mark a model as recently used or add it to the queue\n  public touchModel(modelIdentifier: string): void {\n    // Normalize the model identifier\n    const normalizedId = this.normalizeModelId(modelIdentifier);\n    \n    // Remove the model if it's already in the queue (using normalized ID)\n    this.modelQueue = this.modelQueue.filter(id => this.normalizeModelId(id) !== normalizedId);\n    \n    // Add to the end (most recently used position)\n    this.modelQueue.push(normalizedId);\n    \n    // Schedule a cache check (but don't await it to avoid blocking)\n    setTimeout(() => {\n      this.checkCacheSizeAndCleanup();\n    }, 0);\n  }\n  \n  // Check if cache exceeds threshold and clean up if needed\n  private async checkCacheSizeAndCleanup(): Promise<void> {\n    await this.calculateCacheSizeAsync();\n    \n    if (this.currentCacheSize > this.maxCacheSize * this.cacheThreshold) {\n      console.log(`Cache size (${this.formatBytes(this.currentCacheSize)}) exceeds ${this.cacheThreshold * 100}% threshold (${this.formatBytes(this.maxCacheSize * this.cacheThreshold)})`);\n      \n      // If we have more than one model, remove oldest until we're under threshold\n      while (this.modelQueue.length > 1 && this.currentCacheSize > this.maxCacheSize * this.cacheThreshold) {\n        const oldestModel = this.modelQueue.shift();\n        if (oldestModel) {\n          // Ensure we're using the normalized ID\n          const normalizedId = this.normalizeModelId(oldestModel);\n          console.log(`Removing least recently used model: ${normalizedId}`);\n          await this.removeModelFromCache(normalizedId);\n          await this.calculateCacheSizeAsync();\n        }\n      }\n    }\n  }\n\n  // Delete a specific model from cache\n  public async removeModelFromCache(modelIdentifier: string): Promise<void> {\n    try {\n      const cacheNames = ['webllm/config', 'webllm/wasm', 'webllm/model'];\n      \n      // Normalize the input model identifier\n      const normalizedModelId = this.normalizeModelId(modelIdentifier);\n      console.log(`Removing model: ${modelIdentifier} (normalized: ${normalizedModelId})`);\n      \n      for (const cacheName of cacheNames) {\n        const cache = await caches.open(cacheName);\n        const keys = await cache.keys();\n        \n        const modelKeys = keys.filter(request => {\n          const url = request.url;\n          const rawModelId = this.extractRawModelId(url);\n          if (rawModelId) {\n            const urlNormalizedId = this.normalizeModelId(rawModelId);\n            return urlNormalizedId === normalizedModelId;\n          }\n          return false;\n        });\n        \n        console.log(`Found ${modelKeys.length} entries to remove from ${cacheName}`);\n        \n        // Delete all entries for this model from the current cache\n        await Promise.all(modelKeys.map(key => cache.delete(key)));\n      }\n      \n      console.log(`Successfully removed model ${normalizedModelId} from cache`);\n      \n      // Also remove from our tracking data structures\n      this.modelSizes.delete(normalizedModelId);\n      this.modelQueue = this.modelQueue.filter(id => id !== normalizedModelId);\n    } catch (error) {\n      console.error(`Error removing model ${modelIdentifier} from cache:`, error);\n      throw error;\n    }\n  }\n  \n  // Get current cache statistics with additional debug info\n  public async getCacheInfo(): Promise<{\n    totalSize: number,\n    maxSize: number,\n    usedPercent: number,\n    models: {id: string, size: number, position: number}[],\n    debug: {\n      modelQueueLength: number,\n      modelSizesLength: number,\n      modelQueue: string[]\n    }\n  }> {\n    await this.calculateCacheSizeAsync();\n    \n    return {\n      totalSize: this.currentCacheSize,\n      maxSize: this.maxCacheSize,\n      usedPercent: (this.currentCacheSize / this.maxCacheSize) * 100,\n      models: Array.from(this.modelSizes.entries()).map(([id, size]) => ({\n        id,\n        size,\n        position: this.modelQueue.indexOf(id) + 1\n      })),\n      debug: {\n        modelQueueLength: this.modelQueue.length,\n        modelSizesLength: this.modelSizes.size,\n        modelQueue: [...this.modelQueue]\n      }\n    };\n  }\n\n  // Normalize the entire model queue to ensure consistency\n  private normalizeModelQueue(): void {\n    // Create a new queue with normalized IDs\n    const normalizedQueue: string[] = [];\n    const seenNormalizedIds = new Set<string>();\n    \n    // Process from oldest to newest to maintain LRU order\n    for (const id of this.modelQueue) {\n      const normalizedId = this.normalizeModelId(id);\n      \n      // Only add each normalized ID once (most recent position)\n      if (!seenNormalizedIds.has(normalizedId)) {\n        normalizedQueue.push(normalizedId);\n        seenNormalizedIds.add(normalizedId);\n      }\n    }\n    \n    // Replace the queue with the normalized version\n    this.modelQueue = normalizedQueue;\n    \n    console.log(`Normalized model queue. New length: ${this.modelQueue.length}`);\n  }\n\n  // Estimate available storage and set the cache limit\n  private async estimateAvailableStorageAndSetLimit(): Promise<void> {\n    try {\n      // Check if the Storage API is available\n      if ('storage' in navigator && 'estimate' in navigator.storage) {\n        const estimate = await navigator.storage.estimate();\n        const quota = estimate.quota || 0;\n        const usage = estimate.usage || 0;\n        \n        // Available space is quota minus usage\n        const availableBytes = quota - usage;\n        \n        // Log the storage information\n        console.log(`Storage quota: ${this.formatBytes(quota)}`);\n        console.log(`Current storage usage: ${this.formatBytes(usage)}`);\n        console.log(`Available storage: ${this.formatBytes(availableBytes)}`);\n        \n        // Set our max cache size to 60% of available space, but cap it at 5GB\n        const calculatedMax = Math.min(availableBytes * 0.6, 5 * 1024 * 1024 * 1024);\n        \n        // Ensure we have at least 500MB cache size\n        this.maxCacheSize = Math.max(calculatedMax, 500 * 1024 * 1024);\n        \n        console.log(`Set max cache size to ${this.formatBytes(this.maxCacheSize)} (60% of available space)`);\n      } else {\n        // If Storage API isn't available, use a reasonable default\n        this.maxCacheSize = 1024 * 1024 * 1024; // 1GB default\n        console.log(`Storage API not available. Using default max cache size: ${this.formatBytes(this.maxCacheSize)}`);\n      }\n    } catch (error) {\n      // If there's an error, fall back to a default size\n      this.maxCacheSize = 1024 * 1024 * 1024; // 1GB default\n      console.error('Error estimating storage:', error);\n      console.log(`Using default max cache size: ${this.formatBytes(this.maxCacheSize)}`);\n    }\n  }\n}\n\nexport class MLCEngineWrapper {\n  private mlcEngine: MLCEngineInterface | null = null;\n  private appConfig: AppConfig | null = null;\n  private worker: Worker | null = null;\n  private cacheManager = MLCModelCacheManager.getInstance();\n\n  constructor() {\n    this.mlcEngine = null;\n  }\n\n  async loadModel(modelConfig: ModelConfig, options: MLCLoadModelOptions = {}) {\n    try {\n      if (this.worker) {\n        this.worker.terminate();\n        this.worker = null;\n      }\n\n      if (options.useWorker) {\n        // console.log('[MLCEngine] Creating new worker');\n        \n        const blob = new Blob([workerCode], { type: 'text/javascript' });\n        const workerUrl = URL.createObjectURL(blob);\n        \n        this.worker = new Worker(workerUrl, { \n          type: 'module',\n          name: 'mlc-worker' \n        });\n        \n        URL.revokeObjectURL(workerUrl);\n\n        this.worker.onerror = (error) => {\n          console.error('[MLCEngine] Worker error:', error);\n          throw new Error(`Worker error: ${error.message}`);\n        };\n\n        this.worker.onmessageerror = (error) => {\n          console.error('[MLCEngine] Worker message error:', error);\n        };\n\n        // Wait for worker to be ready\n        await new Promise<void>((resolve, reject) => {\n          if (!this.worker) return reject(new Error('Worker not initialized'));\n\n          const timeout = setTimeout(() => {\n            reject(new Error('Worker initialization timeout'));\n          }, 10000);\n\n          this.worker.onmessage = (msg) => {\n            // console.log('[MLCEngine] Received worker message:', msg.data);\n            if (msg.data.type === 'ready') {\n              clearTimeout(timeout);\n              resolve();\n            } else if (msg.data.type === 'error') {\n              clearTimeout(timeout);\n              reject(new Error(msg.data.error));\n            }\n          };\n\n          // Fix for import.meta.url in CJS environment\n          let moduleURL;\n          try {\n            // Try the ESM approach first\n            moduleURL = new URL('@mlc-ai/web-llm', import.meta.url).href;\n          } catch (e) {\n            // Fallback for CJS environment\n            moduleURL = '@mlc-ai/web-llm';\n            console.log('[MLCEngine] Using module name as fallback for CJS environment');\n          }\n          \n          // Send init message with module URL\n          this.worker.postMessage({\n            type: 'init',\n            moduleURL\n          });\n        });\n\n        // console.log('[MLCEngine] Worker initialized successfully');\n      }\n\n      const quantization = options.quantization || modelConfig.defaultQuantization;\n      const modelIdentifier = modelConfig.repo.replace('{quantization}', quantization).split('/')[1];\n      \n      // Mark this model as recently used in our LRU cache\n      this.cacheManager.touchModel(modelIdentifier);\n      \n      console.log('[MLCEngine] Loading model:', modelIdentifier, 'with worker:', !!this.worker);\n\n      if (modelConfig.modelLibrary) {\n        this.appConfig = {\n          model_list: [\n            {\n              model: \"https://huggingface.co/\" + modelConfig.repo.replace('{quantization}', quantization),\n              model_id: modelIdentifier,\n              model_lib:\n                modelConfig?.modelLibrary?.startsWith('http') ? modelConfig.modelLibrary : (modelLibURLPrefix + '/' +\n                  modelVersion + '/' + modelConfig.modelLibrary),\n            },\n          ],\n        };\n      }\n      else {\n        this.appConfig = prebuiltAppConfig;\n      }\n\n      if (this.worker) {\n        // console.log('[MLCEngine] Creating web worker engine');\n        this.mlcEngine = await CreateWebWorkerMLCEngine(\n          this.worker,\n          modelIdentifier,\n          {\n            initProgressCallback: (progress: any) => {\n              // console.log('[MLCEngine] Loading progress:', progress);\n              options.onProgress?.(progress);\n            },\n            appConfig: this.appConfig,\n            ...options,\n          }\n        );\n        // console.log('[MLCEngine] Web worker engine created successfully');\n      } else {\n        this.mlcEngine = await CreateMLCEngine(modelIdentifier, {\n          initProgressCallback: options.onProgress,\n          appConfig: this.appConfig,\n          ...options,\n        });\n      }\n    } catch (error) {\n      // Clean up worker if initialization failed\n      if (this.worker) {\n        // console.error('[MLCEngine] Error with worker, cleaning up');\n        this.worker.terminate();\n        this.worker = null;\n      }\n      // console.error('[MLCEngine] Error loading model:', error);\n      const message = error instanceof Error ? error.message : String(error);\n      throw new Error(`Failed to load MLC model \"${modelConfig}\": ${message}`);\n    }\n  }\n\n  async generateText(input: string | Record<string, any>[], options: any = {}) {\n    if (!this.mlcEngine) {\n      throw new Error('MLC Engine not initialized.');\n    }\n\n    // Start with system messages\n    let messages: Record<string, any>[] = [];\n    \n    // Combine system prompts into a single message\n    let systemContent = '';\n    \n    if (options.json_schema) {\n      systemContent += 'You must respond with valid JSON that matches the provided schema. Do not include any explanations or additional text.\\n\\n';\n    }\n    \n    if (options.system_prompt) {\n      systemContent += options.system_prompt;\n    }\n\n    // Add combined system message if we have any system content\n    if (systemContent) {\n      messages.push({\n        role: 'system',\n        content: systemContent.trim()\n      });\n    }\n\n    // Then add the user input\n    if (Array.isArray(input)) {\n      messages.push(...input);\n    } else {\n      messages.push({ role: 'user', content: input });\n    }\n\n    // Set default options\n    const defaultOptions = {\n      max_tokens: 300,\n      temperature: 0.6,\n      top_p: 0.95,\n      frequency_penalty: 0.5,\n      presence_penalty: 0.5\n    };\n\n    // Handle JSON schema\n    if (options.json_schema) {\n      // Ensure the schema is properly stringified\n      const schema = typeof options.json_schema === 'string' \n        ? options.json_schema \n        : JSON.stringify(options.json_schema);\n\n      options.response_format = {\n        type: \"json_object\",\n        schema: schema\n      };\n    }\n\n    const finalOptions = {\n      ...defaultOptions,\n      ...options,\n      messages\n    };\n\n    if (options.stream) {\n      finalOptions.stream_options = { include_usage: true };\n      return this.mlcEngine.chat.completions.create(finalOptions);\n    }\n\n    const result = await this.mlcEngine.chat.completions.create(finalOptions);\n    return result;\n  }\n\n  async embed(input: string, options: any = {}) {\n    if (!this.mlcEngine) {\n      throw new Error('MLC Engine not initialized.');\n    }\n    const result = await this.mlcEngine.embeddings.create({ input, ...options });\n    return result.data[0].embedding;\n  }\n\n  dispose() {\n    if (this.worker) {\n      this.worker.terminate();\n      this.worker = null;\n    }\n    this.mlcEngine = null;\n  }\n\n  async clearModelCache(): Promise<void> {\n    return new Promise<void>(async (resolve, reject) => {\n      try {\n        // MLC models are stored in Cache Storage with specific prefixes\n        const cacheNames = ['webllm/config', 'webllm/wasm', 'webllm/model'];\n        \n        // Get all cache names\n        const existingCacheNames = await caches.keys();\n        \n        // Filter caches that match our MLC prefixes\n        const mlcCaches = existingCacheNames.filter(name => \n          cacheNames.some(prefix => name.includes(prefix))\n        );\n        \n        // Delete all matching caches\n        await Promise.all(mlcCaches.map(name => caches.delete(name)));\n        \n        console.log('Successfully cleared MLC model cache');\n        resolve();\n      } catch (error) {\n        console.error('Error clearing model cache:', error);\n        reject(error);\n      }\n    });\n  }\n  \n  async clearSpecificModel(modelIdentifier: string): Promise<void> {\n    if (!modelIdentifier) {\n      throw new Error('Model identifier is required');\n    }\n    return this.cacheManager.removeModelFromCache(modelIdentifier);\n  }\n\n  // Add this new method to the MLCEngineWrapper class\n  async getCacheInfo(): Promise<any> {\n    return this.cacheManager.getCacheInfo();\n  }\n\n  async printCacheInfo(): Promise<void> {\n    const info = await this.cacheManager.getCacheInfo();\n    \n    console.log('=== MLC MODEL CACHE INFORMATION ===');\n    console.log(`Total cache size: ${this.formatBytes(info.totalSize)} of ${this.formatBytes(info.maxSize)} (${info.usedPercent.toFixed(2)}%)`);\n    console.log(`Number of models: ${info.models.length}`);\n    \n    console.log('\\nModels by LRU order (most recently used last):');\n    const sortedModels = [...info.models].sort((a, b) => a.position - b.position);\n    \n    sortedModels.forEach((model, index) => {\n      console.log(`${index + 1}. ${model.id}: ${this.formatBytes(model.size)}`);\n    });\n    \n    console.log('\\nDebug info:');\n    console.log(`Model queue length: ${info.debug.modelQueueLength}`);\n    console.log(`Model sizes map length: ${info.debug.modelSizesLength}`);\n    console.log('LRU Queue order:', info.debug.modelQueue);\n  }\n\n  // Helper method for formatting bytes\n  private formatBytes(bytes: number): string {\n    if (bytes === 0) return '0 Bytes';\n    const k = 1024;\n    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n  }\n}\n","/**\n * @file Module used to configure Transformers.js.\n *\n * **Example:** Disable remote models.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.allowRemoteModels = false;\n * ```\n *\n * **Example:** Set local model path.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.localModelPath = '/path/to/local/models/';\n * ```\n *\n * **Example:** Set cache directory.\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * env.cacheDir = '/path/to/cache/directory/';\n * ```\n *\n * @module env\n */\n\nimport path from 'path';\nimport url from 'url';\n\nconst VERSION = '3.3.3';\n\n// Check if various APIs are available (depends on environment)\nconst IS_BROWSER_ENV = typeof window !== 'undefined' && typeof window.document !== 'undefined';\nconst IS_WEBWORKER_ENV = typeof self !== 'undefined' && self.constructor?.name === 'DedicatedWorkerGlobalScope';\nconst IS_WEB_CACHE_AVAILABLE = typeof self !== 'undefined' && 'caches' in self;\nconst IS_WEBGPU_AVAILABLE = typeof navigator !== 'undefined' && 'gpu' in navigator;\nconst IS_WEBNN_AVAILABLE = typeof navigator !== 'undefined' && 'ml' in navigator;\n\nconst IS_PROCESS_AVAILABLE = typeof process !== 'undefined';\nconst IS_NODE_ENV = IS_PROCESS_AVAILABLE && process?.release?.name === 'node';\nconst IS_FS_AVAILABLE = false;\nconst IS_PATH_AVAILABLE = !isEmpty(path);\n\n/**\n * A read-only object containing information about the APIs available in the current environment.\n */\nexport const apis = Object.freeze({\n  /** Whether we are running in a browser environment (and not a web worker) */\n  IS_BROWSER_ENV,\n\n  /** Whether we are running in a web worker environment */\n  IS_WEBWORKER_ENV,\n\n  /** Whether the Cache API is available */\n  IS_WEB_CACHE_AVAILABLE,\n\n  /** Whether the WebGPU API is available */\n  IS_WEBGPU_AVAILABLE,\n\n  /** Whether the WebNN API is available */\n  IS_WEBNN_AVAILABLE,\n\n  /** Whether the Node.js process API is available */\n  IS_PROCESS_AVAILABLE,\n\n  /** Whether we are running in a Node.js environment */\n  IS_NODE_ENV,\n\n  /** Whether the filesystem API is available */\n  IS_FS_AVAILABLE,\n\n  /** Whether the path API is available */\n  IS_PATH_AVAILABLE,\n});\n\nconst RUNNING_LOCALLY = IS_FS_AVAILABLE && IS_PATH_AVAILABLE;\n\nlet dirname__ = './';\nif (RUNNING_LOCALLY) {\n  // NOTE: We wrap `import.meta` in a call to `Object` to prevent Webpack from trying to bundle it in CommonJS.\n  // Although we get the warning: \"Accessing import.meta directly is unsupported (only property access or destructuring is supported)\",\n  // it is safe to ignore since the bundled value (`{}`) isn't used for CommonJS environments (we use __dirname instead).\n  const _import_meta_url = Object(import.meta).url;\n\n  if (_import_meta_url) {\n    dirname__ = path.dirname(path.dirname(url.fileURLToPath(_import_meta_url))); // ESM\n  } else if (typeof __dirname !== 'undefined') {\n    dirname__ = path.dirname(__dirname); // CommonJS\n  }\n}\n\n// Only used for environments with access to file system\nconst DEFAULT_CACHE_DIR = RUNNING_LOCALLY ? path.join(dirname__, '/.cache/') : null;\n\n// Set local model path, based on available APIs\nconst DEFAULT_LOCAL_MODEL_PATH = '/models/';\nconst localModelPath = RUNNING_LOCALLY ? path.join(dirname__, DEFAULT_LOCAL_MODEL_PATH) : DEFAULT_LOCAL_MODEL_PATH;\n\n/**\n * Global variable given visible to users to control execution. This provides users a simple way to configure Transformers.js.\n * @typedef {Object} TransformersEnvironment\n * @property {string} version This version of Transformers.js.\n * @property {{onnx: Partial<import('onnxruntime-common').Env>}} backends Expose environment variables of different backends,\n * allowing users to set these variables if they want to.\n * @property {boolean} allowRemoteModels Whether to allow loading of remote files, defaults to `true`.\n * If set to `false`, it will have the same effect as setting `local_files_only=true` when loading pipelines, models, tokenizers, processors, etc.\n * @property {string} remoteHost Host URL to load models from. Defaults to the Hugging Face Hub.\n * @property {string} remotePathTemplate Path template to fill in and append to `remoteHost` when loading models.\n * @property {boolean} allowLocalModels Whether to allow loading of local files, defaults to `false` if running in-browser, and `true` otherwise.\n * If set to `false`, it will skip the local file check and try to load the model from the remote host.\n * @property {string} localModelPath Path to load local models from. Defaults to `/models/`.\n * @property {boolean} useFS Whether to use the file system to load files. By default, it is `true` if available.\n * @property {boolean} useBrowserCache Whether to use Cache API to cache models. By default, it is `true` if available.\n * @property {boolean} useFSCache Whether to use the file system to cache files. By default, it is `true` if available.\n * @property {string} cacheDir The directory to use for caching files with the file system. By default, it is `./.cache`.\n * @property {boolean} useCustomCache Whether to use a custom cache system (defined by `customCache`), defaults to `false`.\n * @property {Object} customCache The custom cache to use. Defaults to `null`. Note: this must be an object which\n * implements the `match` and `put` functions of the Web Cache API. For more information, see https://developer.mozilla.org/en-US/docs/Web/API/Cache\n */\n\nexport interface Environment {\n  customCache: {\n    match: (request: string) => Promise<Response | undefined>;\n    put: (request: string, response: Response) => Promise<void>;\n  } | null;\n}\n\n/** @type {TransformersEnvironment} */\nexport const env = {\n  version: VERSION,\n\n  /////////////////// Backends settings ///////////////////\n  // NOTE: These will be populated later by the backends themselves.\n  backends: {\n    // onnxruntime-web/onnxruntime-node\n    onnx: {},\n  },\n\n  /////////////////// Model settings ///////////////////\n  allowRemoteModels: true,\n  remoteHost: 'https://huggingface.co/',\n  remotePathTemplate: '{model}/resolve/{revision}/',\n\n  allowLocalModels: !(IS_BROWSER_ENV || IS_WEBWORKER_ENV),\n  localModelPath: localModelPath,\n  useFS: IS_FS_AVAILABLE,\n\n  /////////////////// Cache settings ///////////////////\n  useBrowserCache: IS_WEB_CACHE_AVAILABLE,\n\n  useFSCache: IS_FS_AVAILABLE,\n  cacheDir: DEFAULT_CACHE_DIR,\n\n  useCustomCache: false,\n  customCache: null,\n  //////////////////////////////////////////////////////\n};\n\n/**\n * @param {Object} obj\n * @private\n */\nfunction isEmpty(obj: any) {\n  return Object.keys(obj).length === 0;\n}\n","export const Callable = /** @type {any} */ class {\n  constructor() {\n    let closure = function (this: any, ...args: any[]): any {\n      return (closure as any)._call(...args);\n    };\n    return Object.setPrototypeOf(closure, new.target.prototype);\n  }\n\n  _call(...args: any[]) {\n    throw Error('Must implement _call method in subclass');\n  }\n};\n","interface InitiateProgressInfo {\n  status: 'initiate';\n  name: string;\n  file: string;\n}\n\ninterface DownloadProgressInfo {\n  status: 'download';\n  name: string;\n  file: string;\n}\n\ninterface ProgressStatusInfo {\n  status: 'progress';\n  name: string;\n  file: string;\n  progress: number;\n  loaded: number;\n  total: number;\n}\n\ninterface DoneProgressInfo {\n  status: 'done';\n  name: string;\n  file: string;\n}\n\ninterface ReadyProgressInfo {\n  status: 'ready';\n  task: string;\n  model: string;\n}\n\nexport type ProgressInfo =\n  | InitiateProgressInfo\n  | DownloadProgressInfo\n  | ProgressStatusInfo\n  | DoneProgressInfo\n  | ReadyProgressInfo;\nexport type ProgressCallback = (progressInfo: ProgressInfo) => void;\n\nexport function dispatchCallback(progress_callback: ProgressCallback | null | undefined, data: ProgressInfo): void {\n  if (progress_callback) progress_callback(data);\n}\n\nexport function reverseDictionary(data: Record<string, any>): Record<string, any> {\n  return Object.fromEntries(Object.entries(data).map(([key, value]) => [value, key]));\n}\n\nexport function escapeRegExp(string: string): string {\n  return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function isTypedArray(val: any): boolean {\n  return val?.prototype?.__proto__?.constructor?.name === 'TypedArray';\n}\n\nexport function isIntegralNumber(x: any): boolean {\n  return Number.isInteger(x) || typeof x === 'bigint';\n}\n\nexport function isNullishDimension(x: any): boolean {\n  return x === null || x === undefined || x === -1;\n}\n\nexport function calculateDimensions(arr: any[]): number[] {\n  const dimensions: number[] = [];\n  let current: any = arr;\n  while (Array.isArray(current)) {\n    dimensions.push(current.length);\n    current = current[0];\n  }\n  return dimensions;\n}\n\nexport function pop<T>(obj: Record<string, T>, key: string, defaultValue?: T): T {\n  const value = obj[key];\n  if (value !== undefined) {\n    delete obj[key];\n    return value;\n  }\n  if (defaultValue === undefined) {\n    throw Error(`Key ${key} does not exist in object.`);\n  }\n  return defaultValue;\n}\n\nexport function mergeArrays<T>(...arrs: T[][]): T[] {\n  return Array.prototype.concat.apply([], arrs);\n}\n\nexport function product<T>(...a: T[][]): T[][] {\n  return a.reduce<T[][]>(\n    (acc, curr) => acc.flatMap((d) => curr.map((e) => [...(Array.isArray(d) ? (d as T[]) : [d]), e])),\n    [[]],\n  );\n}\n\nexport function calculateReflectOffset(i: number, w: number): number {\n  return Math.abs(((i + w) % (2 * w)) - w);\n}\n\n// export function pick<T>(obj: T, keys: Array<keyof T>) {\n//   return Object.fromEntries(keys.map((k) => [k, obj[k as keyof T]]));\n// }\nexport function pick(o: any, props: string[]) {\n    return Object.assign(\n        {},\n        ...props.map((prop: string) => {\n            if (o[prop] !== undefined) {\n        return { [prop]: o[prop] };\n      }\n    }),\n  );\n}\n\nexport function len(s: string): number {\n  let length = 0;\n  for (const c of s) ++length;\n  return length;\n}\n\nexport function count<T>(arr: T[] | string, value: T): number {\n  let count = 0;\n  for (const v of arr) {\n    if (v === value) ++count;\n  }\n  return count;\n}\n\n/**\n * Save blob file on the web.\n * @param {string} path The path to save the blob to\n * @param {Blob} blob The blob to save\n */\nexport function saveBlob(path: string, blob: Blob){\n  // Convert the canvas content to a data URL\n  const dataURL = URL.createObjectURL(blob);\n\n  // Create an anchor element with the data URL as the href attribute\n  const downloadLink = document.createElement('a');\n  downloadLink.href = dataURL;\n\n  // Set the download attribute to specify the desired filename for the downloaded image\n  downloadLink.download = path;\n\n  // Trigger the download\n  downloadLink.click();\n\n  // Clean up: remove the anchor element from the DOM\n  downloadLink.remove();\n\n  // Revoke the Object URL to free up memory\n  URL.revokeObjectURL(dataURL);\n}\n\n","/**\n * @file Utility functions to interact with the Hugging Face Hub (https://huggingface.co/models)\n *\n * @module utils/hub\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { env } from '../env.js';\nimport { dispatchCallback, ProgressCallback } from './core';\nimport { PretrainedConfig } from '../configs';\nexport interface PretrainedOptions {\n  progress_callback?: null | ProgressCallback;\n  config?: null | PretrainedConfig;\n  cache_dir?: null | string;\n  local_files_only?: boolean;\n  revision?: string;\n}\n\n/**\n * @typedef {Object} PretrainedOptions Options for loading a pretrained model.\n * @property {import('./core.js').ProgressCallback} [progress_callback=null] If specified, this function will be called during model construction, to provide the user with progress updates.\n * @property {import('../configs.js').PretrainedConfig} [config=null] Configuration for the model to use instead of an automatically loaded configuration. Configuration can be automatically loaded when:\n * - The model is a model provided by the library (loaded with the *model id* string of a pretrained model).\n * - The model is loaded by supplying a local directory as `pretrained_model_name_or_path` and a configuration JSON file named *config.json* is found in the directory.\n * @property {string} [cache_dir=null] Path to a directory in which a downloaded pretrained model configuration should be cached if the standard cache should not be used.\n * @property {boolean} [local_files_only=false] Whether or not to only look at local files (e.g., not try downloading the model).\n * @property {string} [revision='main'] The specific model version to use. It can be a branch name, a tag name, or a commit id,\n * since we use a git-based system for storing models and other artifacts on huggingface.co, so `revision` can be any identifier allowed by git.\n * NOTE: This setting is ignored for local requests.\n */\n\n/**\n * @typedef {Object} ModelSpecificPretrainedOptions Options for loading a pretrained model.\n * @property {string} [subfolder='onnx'] In case the relevant files are located inside a subfolder of the model repo on huggingface.co,\n * you can specify the folder name here.\n * @property {string} [model_file_name=null] If specified, load the model with this name (excluding the .onnx suffix). Currently only valid for encoder- or decoder-only models.\n * @property {import(\"./devices.js\").DeviceType|Record<string, import(\"./devices.js\").DeviceType>} [device=null] The device to run the model on. If not specified, the device will be chosen from the environment settings.\n * @property {import(\"./dtypes.js\").DataType|Record<string, import(\"./dtypes.js\").DataType>} [dtype=null] The data type to use for the model. If not specified, the data type will be chosen from the environment settings.\n * @property {boolean|Record<string, boolean>} [use_external_data_format=false] Whether to load the model using the external data format (used for models >= 2GB in size).\n * @property {import('onnxruntime-common').InferenceSession.SessionOptions} [session_options] (Optional) User-specified session options passed to the runtime. If not provided, suitable defaults will be chosen.\n */\n\n/**\n * @typedef {PretrainedOptions & ModelSpecificPretrainedOptions} PretrainedModelOptions Options for loading a pretrained model.\n */\n\n/**\n * Mapping from file extensions to MIME types.\n */\nconst CONTENT_TYPE_MAP = {\n  txt: 'text/plain',\n  html: 'text/html',\n  css: 'text/css',\n  js: 'text/javascript',\n  json: 'application/json',\n  png: 'image/png',\n  jpg: 'image/jpeg',\n  jpeg: 'image/jpeg',\n  gif: 'image/gif',\n};\nclass FileResponse {\n  filePath: string | URL;\n  headers: Headers;\n  exists: boolean;\n  status: number;\n  statusText: string;\n  body: ReadableStream<Uint8Array> | null;\n\n  /**\n   * Creates a new `FileResponse` object.\n   * @param {string|URL} filePath\n   */\n  constructor(filePath: string | URL) {\n    this.filePath = filePath;\n    this.headers = new Headers();\n\n    this.exists = fs.existsSync(filePath);\n    if (this.exists) {\n      this.status = 200;\n      this.statusText = 'OK';\n\n      let stats = fs.statSync(filePath);\n      this.headers.set('content-length', stats.size.toString());\n\n      this.updateContentType();\n\n      let self = this;\n      this.body = new ReadableStream({\n        start(controller) {\n          self.arrayBuffer().then((buffer) => {\n            controller.enqueue(new Uint8Array(buffer));\n            controller.close();\n          });\n        },\n      });\n    } else {\n      this.status = 404;\n      this.statusText = 'Not Found';\n      this.body = null;\n    }\n  }\n\n  /**\n   * Updates the 'content-type' header property of the response based on the extension of\n   * the file specified by the filePath property of the current object.\n   * @returns {void}\n   */\n  updateContentType() {\n    // Set content-type header based on file extension\n    const extension = this.filePath.toString().split('.').pop()?.toLowerCase();\n    this.headers.set(\n      'content-type',\n      CONTENT_TYPE_MAP[extension as keyof typeof CONTENT_TYPE_MAP] ?? 'application/octet-stream',\n    );\n  }\n\n  /**\n   * Clone the current FileResponse object.\n   * @returns {FileResponse} A new FileResponse object with the same properties as the current object.\n   */\n  clone() {\n    let response = new FileResponse(this.filePath);\n    response.exists = this.exists;\n    response.status = this.status;\n    response.statusText = this.statusText;\n    response.headers = new Headers(this.headers);\n    return response;\n  }\n\n  /**\n   * Reads the contents of the file specified by the filePath property and returns a Promise that\n   * resolves with an ArrayBuffer containing the file's contents.\n   * @returns {Promise<ArrayBuffer>} A Promise that resolves with an ArrayBuffer containing the file's contents.\n   * @throws {Error} If the file cannot be read.\n   */\n  async arrayBuffer() {\n    const data = await fs.promises.readFile(this.filePath);\n    return /** @type {ArrayBuffer} */ data.buffer;\n  }\n\n  /**\n   * Reads the contents of the file specified by the filePath property and returns a Promise that\n   * resolves with a Blob containing the file's contents.\n   * @returns {Promise<Blob>} A Promise that resolves with a Blob containing the file's contents.\n   * @throws {Error} If the file cannot be read.\n   */\n  async blob() {\n    const data = await fs.promises.readFile(this.filePath);\n    return new Blob([data], { type: this.headers.get('content-type') as string });\n  }\n\n  /**\n   * Reads the contents of the file specified by the filePath property and returns a Promise that\n   * resolves with a string containing the file's contents.\n   * @returns {Promise<string>} A Promise that resolves with a string containing the file's contents.\n   * @throws {Error} If the file cannot be read.\n   */\n  async text() {\n    const data = await fs.promises.readFile(this.filePath, 'utf8');\n    return data;\n  }\n\n  /**\n   * Reads the contents of the file specified by the filePath property and returns a Promise that\n   * resolves with a parsed JavaScript object containing the file's contents.\n   *\n   * @returns {Promise<Object>} A Promise that resolves with a parsed JavaScript object containing the file's contents.\n   * @throws {Error} If the file cannot be read.\n   */\n  async json() {\n    return JSON.parse(await this.text());\n  }\n}\n\n/**\n * Determines whether the given string is a valid URL.\n * @param {string|URL} string The string to test for validity as an URL.\n * @param {string[]} [protocols=null] A list of valid protocols. If specified, the protocol must be in this list.\n * @param {string[]} [validHosts=null] A list of valid hostnames. If specified, the URL's hostname must be in this list.\n * @returns {boolean} True if the string is a valid URL, false otherwise.\n */\nfunction isValidUrl(string: string, protocols: string[] | null = null, validHosts: string[] | null = null) {\n  let url;\n  try {\n    url = new URL(string);\n  } catch (_) {\n    return false;\n  }\n  if (protocols && !protocols.includes(url.protocol)) {\n    return false;\n  }\n  if (validHosts && !validHosts.includes(url.hostname)) {\n    return false;\n  }\n  return true;\n}\n\n/**\n * Helper function to get a file, using either the Fetch API or FileSystem API.\n *\n * @param {URL|string} urlOrPath The URL/path of the file to get.\n * @returns {Promise<FileResponse|Response>} A promise that resolves to a FileResponse object (if the file is retrieved using the FileSystem API), or a Response object (if the file is retrieved using the Fetch API).\n */\nexport async function getFile(urlOrPath: URL | string) {\n  if (env.useFS && !isValidUrl(urlOrPath.toString(), ['http:', 'https:', 'blob:'])) {\n    return new FileResponse(urlOrPath);\n  } else if (typeof process !== 'undefined' && process?.release?.name === 'node') {\n    const IS_CI = false;\n    const version = env.version;\n\n    const headers = new Headers();\n    headers.set('User-Agent', `transformers.js/${version}; is_ci/${IS_CI};`);\n\n    // Check whether we are making a request to the Hugging Face Hub.\n    const isHFURL = isValidUrl(urlOrPath.toString(), ['http:', 'https:'], ['huggingface.co', 'hf.co']);\n    if (isHFURL) {\n      // If an access token is present in the environment variables,\n      // we add it to the request headers.\n      // NOTE: We keep `HF_ACCESS_TOKEN` for backwards compatibility (as a fallback).\n      const token = process.env?.HF_TOKEN ?? process.env?.HF_ACCESS_TOKEN;\n      if (token) {\n        headers.set('Authorization', `Bearer ${token}`);\n      }\n    }\n    return fetch(urlOrPath, { headers });\n  } else {\n    // Running in a browser-environment, so we use default headers\n    // NOTE: We do not allow passing authorization headers in the browser,\n    // since this would require exposing the token to the client.\n    return fetch(urlOrPath);\n  }\n}\n\nconst ERROR_MAPPING = {\n  // 4xx errors (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses)\n  400: 'Bad request error occurred while trying to load file',\n  401: 'Unauthorized access to file',\n  403: 'Forbidden access to file',\n  404: 'Could not locate file',\n  408: 'Request timeout error occurred while trying to load file',\n\n  // 5xx errors (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses)\n  500: 'Internal server error error occurred while trying to load file',\n  502: 'Bad gateway error occurred while trying to load file',\n  503: 'Service unavailable error occurred while trying to load file',\n  504: 'Gateway timeout error occurred while trying to load file',\n};\n/**\n * Helper method to handle fatal errors that occur while trying to load a file from the Hugging Face Hub.\n * @param {number} status The HTTP status code of the error.\n * @param {string} remoteURL The URL of the file that could not be loaded.\n * @param {boolean} fatal Whether to raise an error if the file could not be loaded.\n * @returns {null} Returns `null` if `fatal = true`.\n * @throws {Error} If `fatal = false`.\n */\nfunction handleError(status: number, remoteURL: string, fatal: boolean) {\n  if (!fatal) {\n    // File was not loaded correctly, but it is optional.\n    // TODO in future, cache the response?\n    return null;\n  }\n\n  const message =\n    ERROR_MAPPING[status as keyof typeof ERROR_MAPPING] ?? `Error (${status}) occurred while trying to load file`;\n  throw Error(`${message}: \"${remoteURL}\".`);\n}\n\nclass FileCache {\n  private path: string;\n  private cache:  Map<string, ArrayBuffer>;\n\n  /**\n   * Instantiate a `FileCache` object.\n   * @param {string} path\n   */\n  constructor(path: string) {\n    this.path = path;\n    this.cache = new Map();\n  }\n\n  /**\n   * Checks whether the given request is in the cache.\n   * @param {string} request\n   * @returns {Promise<FileResponse | undefined>}\n   */\n  async match(request: string) {\n    let filePath = path.join(this.path, request);\n    let file = new FileResponse(filePath);\n\n    if (file.exists) {\n      return file;\n    } else {\n      return undefined;\n    }\n  }\n\n  /**\n   * Adds the given response to the cache.\n   * @param {string} request\n   * @param {Response|FileResponse} response\n   * @returns {Promise<void>}\n   */\n  async put(request: string, response: Response | FileResponse) {\n    const buffer = Buffer.from(await response.arrayBuffer());\n\n    let outputPath = path.join(this.path, request);\n\n    try {\n      await fs.promises.mkdir(path.dirname(outputPath), { recursive: true });\n      await fs.promises.writeFile(outputPath, buffer);\n    } catch (err) {\n      console.warn('An error occurred while writing the file to cache:', err);\n    }\n  }\n\n  // TODO add the rest?\n  // addAll(requests: RequestInfo[]): Promise<void>;\n  // delete(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<boolean>;\n  // keys(request?: RequestInfo | URL, options?: CacheQueryOptions): Promise<ReadonlyArray<Request>>;\n  // match(request: RequestInfo | URL, options?: CacheQueryOptions): Promise<Response | undefined>;\n  // matchAll(request?: RequestInfo | URL, options?: CacheQueryOptions): Promise<ReadonlyArray<Response>>;\n}\n\n/**\n *\n * @param {FileCache|Cache} cache The cache to search\n * @param {string[]} names The names of the item to search for\n * @returns {Promise<FileResponse|Response|undefined>} The item from the cache, or undefined if not found.\n */\nasync function tryCache(cache: FileCache | Cache, ...names: string[]) {\n  for (let name of names) {\n    try {\n      let result = await cache.match(name);\n      if (result) return result;\n    } catch (e) {\n      continue;\n    }\n  }\n  return undefined;\n}\n\n/**\n *\n * Retrieves a file from either a remote URL using the Fetch API or from the local file system using the FileSystem API.\n * If the filesystem is available and `env.useCache = true`, the file will be downloaded and cached.\n *\n * @param {string} path_or_repo_id This can be either:\n * - a string, the *model id* of a model repo on huggingface.co.\n * - a path to a *directory* potentially containing the file.\n * @param {string} filename The name of the file to locate in `path_or_repo`.\n * @param {boolean} [fatal=true] Whether to throw an error if the file is not found.\n * @param {PretrainedOptions} [options] An object containing optional parameters.\n *\n * @throws Will throw an error if the file is not found and `fatal` is true.\n * @returns {Promise<Uint8Array>} A Promise that resolves with the file content as a buffer.\n */\nexport async function getModelFile(\n  path_or_repo_id: string,\n  filename: string,\n  fatal = true,\n  options: PretrainedOptions = {},\n) {\n  if (!env.allowLocalModels) {\n    // User has disabled local models, so we just make sure other settings are correct.\n\n    if (options.local_files_only) {\n      throw Error(\n        'Invalid configuration detected: local models are disabled (`env.allowLocalModels=false`) but you have requested to only use local models (`local_files_only=true`).',\n      );\n    } else if (!env.allowRemoteModels) {\n      throw Error(\n        'Invalid configuration detected: both local and remote models are disabled. Fix by setting `env.allowLocalModels` or `env.allowRemoteModels` to `true`.',\n      );\n    }\n  }\n\n  // Initiate file retrieval\n  dispatchCallback(options.progress_callback, {\n    status: 'initiate',\n    name: path_or_repo_id,\n    file: filename,\n  });\n\n  // First, check if the a caching backend is available\n  // If no caching mechanism available, will download the file every time\n  let cache;\n  if (!cache && env.useBrowserCache) {\n    if (typeof caches === 'undefined') {\n      throw Error('Browser cache is not available in this environment.');\n    }\n    try {\n      // In some cases, the browser cache may be visible, but not accessible due to security restrictions.\n      // For example, when running an application in an iframe, if a user attempts to load the page in\n      // incognito mode, the following error is thrown: `DOMException: Failed to execute 'open' on 'CacheStorage':\n      // An attempt was made to break through the security policy of the user agent.`\n      // So, instead of crashing, we just ignore the error and continue without using the cache.\n      cache = await caches.open('transformers-cache');\n    } catch (e) {\n      console.warn('An error occurred while opening the browser cache:', e);\n    }\n  }\n\n  if (!cache && env.useFSCache) {\n    // TODO throw error if not available\n\n    // If `cache_dir` is not specified, use the default cache directory\n    cache = new FileCache(options.cache_dir ?? env.cacheDir ?? '');\n  }\n\n  if (!cache && env.useCustomCache) {\n    // Allow the user to specify a custom cache system.\n    if (!env.customCache) {\n      throw Error('`env.useCustomCache=true`, but `env.customCache` is not defined.');\n    }\n\n    // Check that the required methods are defined:\n    if (!(env.customCache as Cache).match || !(env.customCache as Cache).put) {\n      throw new Error(\n        '`env.customCache` must be an object which implements the `match` and `put` functions of the Web Cache API. ' +\n          'For more information, see https://developer.mozilla.org/en-US/docs/Web/API/Cache',\n      );\n    }\n    cache = env.customCache;\n  }\n\n  const revision = options.revision ?? 'main';\n\n  let requestURL = pathJoin(path_or_repo_id, filename);\n  let localPath = pathJoin(env.localModelPath, requestURL);\n\n  let remoteURL = pathJoin(\n    env.remoteHost,\n    env.remotePathTemplate\n      .replaceAll('{model}', path_or_repo_id)\n      .replaceAll('{revision}', encodeURIComponent(revision)),\n    filename,\n  );\n\n  // Choose cache key for filesystem cache\n  // When using the main revision (default), we use the request URL as the cache key.\n  // If a specific revision is requested, we account for this in the cache key.\n  let fsCacheKey = revision === 'main' ? requestURL : pathJoin(path_or_repo_id, revision, filename);\n\n  /** @type {string} */\n  let cacheKey;\n  let proposedCacheKey = cache instanceof FileCache ? fsCacheKey : remoteURL;\n\n  // Whether to cache the final response in the end.\n  let toCacheResponse = false;\n\n  /** @type {Response|FileResponse|undefined} */\n  let response;\n\n  if (cache) {\n    // A caching system is available, so we try to get the file from it.\n    //  1. We first try to get from cache using the local path. In some environments (like deno),\n    //     non-URL cache keys are not allowed. In these cases, `response` will be undefined.\n    //  2. If no response is found, we try to get from cache using the remote URL or file system cache.\n    response = await tryCache(cache, localPath, proposedCacheKey);\n  }\n\n  const cacheHit = response !== undefined;\n\n  if (response === undefined) {\n    // Caching not available, or file is not cached, so we perform the request\n\n    if (env.allowLocalModels) {\n      // Accessing local models is enabled, so we try to get the file locally.\n      // If request is a valid HTTP URL, we skip the local file check. Otherwise, we try to get the file locally.\n      const isURL = isValidUrl(requestURL, ['http:', 'https:']);\n      if (!isURL) {\n        try {\n          response = await getFile(localPath);\n          cacheKey = localPath; // Update the cache key to be the local path\n        } catch (e) {\n          // Something went wrong while trying to get the file locally.\n          // NOTE: error handling is done in the next step (since `response` will be undefined)\n          console.warn(`Unable to load from local path \"${localPath}\": \"${e}\"`);\n        }\n      } else if (options.local_files_only) {\n        throw new Error(`\\`local_files_only=true\\`, but attempted to load a remote file from: ${requestURL}.`);\n      } else if (!env.allowRemoteModels) {\n        throw new Error(`\\`env.allowRemoteModels=false\\`, but attempted to load a remote file from: ${requestURL}.`);\n      }\n    }\n\n    if (response === undefined || response.status === 404) {\n      // File not found locally. This means either:\n      // - The user has disabled local file access (`env.allowLocalModels=false`)\n      // - the path is a valid HTTP url (`response === undefined`)\n      // - the path is not a valid HTTP url and the file is not present on the file system or local server (`response.status === 404`)\n\n      if (options.local_files_only || !env.allowRemoteModels) {\n        // User requested local files only, but the file is not found locally.\n        if (fatal) {\n          throw Error(\n            `\\`local_files_only=true\\` or \\`env.allowRemoteModels=false\\` and file was not found locally at \"${localPath}\".`,\n          );\n        } else {\n          // File not found, but this file is optional.\n          // TODO in future, cache the response?\n          return null;\n        }\n      }\n\n      // File not found locally, so we try to download it from the remote server\n      response = await getFile(remoteURL);\n\n      if (response.status !== 200) {\n        return handleError(response.status, remoteURL, fatal);\n      }\n\n      // Success! We use the proposed cache key from earlier\n      cacheKey = proposedCacheKey;\n    }\n\n    // Only cache the response if:\n    toCacheResponse = !!(\n      cache && // 1. A caching system is available\n      typeof Response !== 'undefined' // 2. `Response` is defined (i.e., we are in a browser-like environment)\n    );\n  }\n\n  // Start downloading\n  dispatchCallback(options.progress_callback, {\n    status: 'download',\n    name: path_or_repo_id,\n    file: filename,\n  });\n\n  /** @type {Uint8Array} */\n  let buffer;\n\n  if (!options.progress_callback) {\n    // If no progress callback is specified, we can use the `.arrayBuffer()`\n    // method to read the response.\n    buffer = new Uint8Array(await response.arrayBuffer());\n  } else if (\n    cacheHit && // The item is being read from the cache\n    typeof navigator !== 'undefined' &&\n    /firefox/i.test(navigator.userAgent) // We are in Firefox\n  ) {\n    // Due to bug in Firefox, we cannot display progress when loading from cache.\n    // Fortunately, since this should be instantaneous, this should not impact users too much.\n    buffer = new Uint8Array(await response.arrayBuffer());\n\n    // For completeness, we still fire the final progress callback\n    dispatchCallback(options.progress_callback, {\n      status: 'progress',\n      name: path_or_repo_id,\n      file: filename,\n      progress: 100,\n      loaded: buffer.length,\n      total: buffer.length,\n    });\n  } else {\n    if (response instanceof FileResponse) {\n      throw new Error('FileResponse is not supported');\n    }\n    buffer = await readResponse(response, (data) => {\n      dispatchCallback(options.progress_callback, {\n        status: 'progress',\n        name: path_or_repo_id,\n        file: filename,\n        ...data,\n      });\n    });\n  }\n\n  if (\n    // Only cache web responses\n    // i.e., do not cache FileResponses (prevents duplication)\n    toCacheResponse &&\n    cacheKey &&\n    // Check again whether request is in cache. If not, we add the response to the cache\n    (await cache?.match(cacheKey)) === undefined\n  ) {\n    // NOTE: We use `new Response(buffer, ...)` instead of `response.clone()` to handle LFS files\n    await cache\n      ?.put(\n        cacheKey,\n        new Response(buffer, {\n          headers: response.headers,\n        }),\n      )\n      .catch((err) => {\n        // Do not crash if unable to add to cache (e.g., QuotaExceededError).\n        // Rather, log a warning and proceed with execution.\n        console.warn(`Unable to add response to browser cache: ${err}.`);\n      });\n  }\n\n  dispatchCallback(options.progress_callback, {\n    status: 'done',\n    name: path_or_repo_id,\n    file: filename,\n  });\n\n  return buffer;\n}\n\n/**\n * Fetches a JSON file from a given path and file name.\n *\n * @param {string} modelPath The path to the directory containing the file.\n * @param {string} fileName The name of the file to fetch.\n * @param {boolean} [fatal=true] Whether to throw an error if the file is not found.\n * @param {PretrainedOptions} [options] An object containing optional parameters.\n * @returns {Promise<Object>} The JSON data parsed into a JavaScript object.\n * @throws Will throw an error if the file is not found and `fatal` is true.\n */\nexport async function getModelJSON(modelPath: string, fileName: string, fatal = true, options = {}) {\n  let buffer = await getModelFile(modelPath, fileName, fatal, options);\n  if (buffer === null) {\n    // Return empty object\n    return {};\n  }\n\n  let decoder = new TextDecoder('utf-8');\n  let jsonData = decoder.decode(buffer);\n\n  return JSON.parse(jsonData);\n}\n/**\n * Read and track progress when reading a Response object\n *\n * @param {Response|FileResponse} response The Response object to read\n * @param {(data: {progress: number, loaded: number, total: number}) => void} progress_callback The function to call with progress updates\n * @returns {Promise<Uint8Array>} A Promise that resolves with the Uint8Array buffer\n */\nexport async function readResponse(\n  response: Response,\n  progress_callback: (data: { progress: number; loaded: number; total: number }) => void,\n) {\n  const contentLength = response.headers.get('Content-Length');\n  if (contentLength === null) {\n    console.warn('Unable to determine content-length from response headers. Will expand buffer when needed.');\n  }\n  let total = parseInt(contentLength ?? '0');\n  let buffer = new Uint8Array(total);\n  let loaded = 0;\n\n  const reader = response.body?.getReader();\n  if (!reader) throw new Error('Response body reader is undefined');\n\n  async function read() {\n    const { done, value } = await reader?.read()!;\n    if (done) return;\n\n    let newLoaded = loaded + value.length;\n    if (newLoaded > total) {\n      total = newLoaded;\n\n      // Adding the new data will overflow buffer.\n      // In this case, we extend the buffer\n      let newBuffer = new Uint8Array(total);\n\n      // copy contents\n      newBuffer.set(buffer);\n\n      buffer = newBuffer;\n    }\n    buffer.set(value, loaded);\n    loaded = newLoaded;\n\n    const progress = (loaded / total) * 100;\n\n    // Call your function here\n    progress_callback({\n      progress: progress,\n      loaded: loaded,\n      total: total,\n    });\n\n    return read();\n  }\n\n  // Actually read\n  await read();\n\n  return buffer;\n}\n\nexport function pathJoin(...parts: string[]) {\n  // https://stackoverflow.com/a/55142565\n  parts = parts.map((part, index) => {\n    if (index) {\n      part = part.replace(new RegExp('^/'), '');\n    }\n    if (index !== parts.length - 1) {\n      part = part.replace(new RegExp('/$'), '');\n    }\n    return part;\n  });\n  return parts.join('/');\n}\n","/**\n * @file Helper module for mathematical processing.\n *\n * These functions and classes are only used internally,\n * meaning an end-user shouldn't need to access anything here.\n *\n * @module utils/maths\n */\n\n/**\n * @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array} TypedArray\n * @typedef {BigInt64Array | BigUint64Array} BigTypedArray\n * @typedef {TypedArray | BigTypedArray} AnyTypedArray\n */\n\n/**\n * @param {TypedArray} input\n */\n\ntype TypedArray =\n  | Int8Array\n  | Uint8Array\n  | Uint8ClampedArray\n  | Int16Array\n  | Uint16Array\n  | Int32Array\n  | Uint32Array\n  | Float32Array\n  | Float64Array;\ntype BigTypedArray = BigInt64Array | BigUint64Array;\ntype AnyTypedArray = TypedArray | BigTypedArray;\n\nexport function interpolate_data(\n  input: TypedArray,\n  [in_channels, in_height, in_width]: [number, number, number],\n  [out_height, out_width]: [number, number],\n  mode = 'bilinear',\n  align_corners = false,\n) {\n  // TODO use mode and align_corners\n\n  // Output image dimensions\n  const x_scale = out_width / in_width;\n  const y_scale = out_height / in_height;\n\n  // Output image\n  // @ts-ignore\n  const out_img = new input.constructor(out_height * out_width * in_channels);\n\n  // Pre-calculate strides\n  const inStride = in_height * in_width;\n  const outStride = out_height * out_width;\n\n  for (let i = 0; i < out_height; ++i) {\n    for (let j = 0; j < out_width; ++j) {\n      // Calculate output offset\n      const outOffset = i * out_width + j;\n\n      // Calculate input pixel coordinates\n      const x = (j + 0.5) / x_scale - 0.5;\n      const y = (i + 0.5) / y_scale - 0.5;\n\n      // Calculate the four nearest input pixels\n      // We also check if the input pixel coordinates are within the image bounds\n      let x1 = Math.floor(x);\n      let y1 = Math.floor(y);\n      const x2 = Math.min(x1 + 1, in_width - 1);\n      const y2 = Math.min(y1 + 1, in_height - 1);\n\n      x1 = Math.max(x1, 0);\n      y1 = Math.max(y1, 0);\n\n      // Calculate the fractional distances between the input pixel and the four nearest pixels\n      const s = x - x1;\n      const t = y - y1;\n\n      // Perform bilinear interpolation\n      const w1 = (1 - s) * (1 - t);\n      const w2 = s * (1 - t);\n      const w3 = (1 - s) * t;\n      const w4 = s * t;\n\n      // Calculate the four nearest input pixel indices\n      const yStride = y1 * in_width;\n      const xStride = y2 * in_width;\n      const idx1 = yStride + x1;\n      const idx2 = yStride + x2;\n      const idx3 = xStride + x1;\n      const idx4 = xStride + x2;\n\n      for (let k = 0; k < in_channels; ++k) {\n        // Calculate channel offset\n        const cOffset = k * inStride;\n\n        out_img[k * outStride + outOffset] =\n          w1 * input[cOffset + idx1] +\n          w2 * input[cOffset + idx2] +\n          w3 * input[cOffset + idx3] +\n          w4 * input[cOffset + idx4];\n      }\n    }\n  }\n\n  return out_img;\n}\n\n/**\n * Helper method to permute a `AnyTypedArray` directly\n * @template {AnyTypedArray} T\n * @param {T} array\n * @param {number[]} dims\n * @param {number[]} axes\n * @returns {[T, number[]]} The permuted array and the new shape.\n */\nexport function permute_data(array: TypedArray, dims: number[], axes: number[]) {\n  // Calculate the new shape of the permuted array\n  // and the stride of the original array\n  const shape = new Array(axes.length);\n  const stride = new Array(axes.length);\n\n  for (let i = axes.length - 1, s = 1; i >= 0; --i) {\n    stride[i] = s;\n    shape[i] = dims[axes[i]];\n    s *= shape[i];\n  }\n\n  // Precompute inverse mapping of stride\n  const invStride = axes.map((_, i) => stride[axes.indexOf(i)]);\n\n  // Create the permuted array with the new shape\n  // @ts-ignore\n  const permutedData = new array.constructor(array.length);\n\n  // Permute the original array to the new array\n  for (let i = 0; i < array.length; ++i) {\n    let newIndex = 0;\n    for (let j = dims.length - 1, k = i; j >= 0; --j) {\n      newIndex += (k % dims[j]) * invStride[j];\n      k = Math.floor(k / dims[j]);\n    }\n    permutedData[newIndex] = array[i];\n  }\n\n  return [permutedData, shape];\n}\n\n/**\n * Compute the softmax of an array of numbers.\n * @template {TypedArray|number[]} T\n * @param {T} arr The array of numbers to compute the softmax of.\n * @returns {T} The softmax array.\n */\nexport function softmax(arr: TypedArray | number[]) {\n  // Compute the maximum value in the array\n  const maxVal = max(arr)[0];\n\n  // Compute the exponentials of the array values\n  const exps = arr.map((x) => {\n    if (typeof maxVal === 'bigint') {\n      // Convert to Number only if within safe integer range\n      if (maxVal <= BigInt(Number.MAX_SAFE_INTEGER)) {\n        return Math.exp(Number(x) - Number(maxVal));\n      }\n      throw new Error('BigInt value exceeds safe number range for exponential calculation');\n    }\n    return Math.exp(Number(x) - maxVal);\n  });\n\n  // Compute the sum of the exponentials\n  // @ts-ignore\n  const sumExps = exps.reduce((acc, val) => acc + val, 0);\n\n  // Compute the softmax values\n  const softmaxArr = exps.map((x) => x / sumExps);\n\n  return /** @type {T} */ softmaxArr;\n}\n\n/**\n * Calculates the logarithm of the softmax function for the input array.\n * @template {TypedArray|number[]} T\n * @param {T} arr The input array to calculate the log_softmax function for.\n * @returns {T} The resulting log_softmax array.\n */\nexport function log_softmax(arr: TypedArray | number[]) {\n  // Compute the maximum value in the array\n  const maxVal = max(arr)[0];\n\n  // Compute the sum of the exponentials\n  let sumExps = 0;\n  for (let i = 0; i < arr.length; ++i) {\n    if (typeof maxVal === 'bigint') {\n      if (maxVal <= BigInt(Number.MAX_SAFE_INTEGER)) {\n        sumExps += Math.exp(Number(arr[i]) - Number(maxVal));\n      }\n      throw new Error('BigInt value exceeds safe number range for exponential calculation');\n    }\n    sumExps += Math.exp(Number(arr[i]) - maxVal);\n  }\n\n  // Compute the log of the sum\n  const logSum = Math.log(sumExps);\n\n  // Compute the softmax values\n  const logSoftmaxArr = arr.map((x) => {\n    if (typeof maxVal === 'bigint') {\n      return Number(x) - Number(maxVal) - logSum;\n    }\n    return Number(x) - maxVal - logSum;\n  });\n\n  return /** @type {T} */ logSoftmaxArr;\n}\n\n/**\n * Calculates the dot product of two arrays.\n * @param {number[]} arr1 The first array.\n * @param {number[]} arr2 The second array.\n * @returns {number} The dot product of arr1 and arr2.\n */\nexport function dot(arr1: number[], arr2: number[]) {\n  let result = 0;\n  for (let i = 0; i < arr1.length; ++i) {\n    result += arr1[i] * arr2[i];\n  }\n  return result;\n}\n\n/**\n * Computes the cosine similarity between two arrays.\n *\n * @param {number[]} arr1 The first array.\n * @param {number[]} arr2 The second array.\n * @returns {number} The cosine similarity between the two arrays.\n */\nexport function cos_sim(arr1: number[], arr2: number[]) {\n  // Calculate dot product of the two arrays\n  const dotProduct = dot(arr1, arr2);\n\n  // Calculate the magnitude of the first array\n  const magnitudeA = magnitude(arr1);\n\n  // Calculate the magnitude of the second array\n  const magnitudeB = magnitude(arr2);\n\n  // Calculate the cosine similarity\n  const cosineSimilarity = dotProduct / (magnitudeA * magnitudeB);\n\n  return cosineSimilarity;\n}\n\n/**\n * Calculates the magnitude of a given array.\n * @param {number[]} arr The array to calculate the magnitude of.\n * @returns {number} The magnitude of the array.\n */\nexport function magnitude(arr: number[]) {\n  return Math.sqrt(arr.reduce((acc, val) => acc + val * val, 0));\n}\n\n/**\n * Returns the value and index of the minimum element in an array.\n * @template {number[]|bigint[]|AnyTypedArray} T\n * @param {T} arr array of numbers.\n * @returns {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} the value and index of the minimum element, of the form: [valueOfMin, indexOfMin]\n * @throws {Error} If array is empty.\n */\nexport function min(arr: number[] | bigint[] | TypedArray) {\n  if (arr.length === 0) throw Error('Array must not be empty');\n  let min = arr[0];\n  let indexOfMin = 0;\n  for (let i = 1; i < arr.length; ++i) {\n    if (arr[i] < min) {\n      min = arr[i];\n      indexOfMin = i;\n    }\n  }\n  return /** @type {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} */ [min, indexOfMin];\n}\n\n/**\n * Returns the value and index of the maximum element in an array.\n * @template {number[]|bigint[]|AnyTypedArray} T\n * @param {T} arr array of numbers.\n * @returns {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} the value and index of the maximum element, of the form: [valueOfMax, indexOfMax]\n * @throws {Error} If array is empty.\n */\nexport function max(arr: number[] | bigint[] | TypedArray) {\n  if (arr.length === 0) throw Error('Array must not be empty');\n  let max = arr[0];\n  let indexOfMax = 0;\n  for (let i = 1; i < arr.length; ++i) {\n    if (arr[i] > max) {\n      max = arr[i];\n      indexOfMax = i;\n    }\n  }\n  return /** @type {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} */ [max, indexOfMax];\n}\n\nfunction isPowerOfTwo(number: number) {\n  // Check if the number is greater than 0 and has only one bit set to 1\n  return number > 0 && (number & (number - 1)) === 0;\n}\n\n/**\n * Implementation of Radix-4 FFT.\n *\n * P2FFT class provides functionality for performing Fast Fourier Transform on arrays\n * which are a power of two in length.\n * Code adapted from https://www.npmjs.com/package/fft.js\n */\nclass P2FFT {\n  /**\n   * @param {number} size The size of the input array. Must be a power of two larger than 1.\n   * @throws {Error} FFT size must be a power of two larger than 1.\n   */\n  private size: number;\n  private _csize: number;\n  private _width: number;\n  private _bitrev: Int32Array;\n  private table: Float64Array;\n\n  constructor(size: number) {\n    this.size = size | 0; // convert to a 32-bit signed integer\n    if (this.size <= 1 || !isPowerOfTwo(this.size)) throw new Error('FFT size must be a power of two larger than 1');\n\n    this._csize = size << 1;\n\n    this.table = new Float64Array(this.size * 2);\n    for (let i = 0; i < this.table.length; i += 2) {\n      const angle = (Math.PI * i) / this.size;\n      this.table[i] = Math.cos(angle);\n      this.table[i + 1] = -Math.sin(angle);\n    }\n\n    // Find size's power of two\n    let power = 0;\n    for (let t = 1; this.size > t; t <<= 1) ++power;\n\n    // Calculate initial step's width:\n    //   * If we are full radix-4, it is 2x smaller to give inital len=8\n    //   * Otherwise it is the same as `power` to give len=4\n    this._width = power % 2 === 0 ? power - 1 : power;\n\n    // Pre-compute bit-reversal patterns\n    this._bitrev = new Int32Array(1 << this._width);\n    for (let j = 0; j < this._bitrev.length; ++j) {\n      this._bitrev[j] = 0;\n      for (let shift = 0; shift < this._width; shift += 2) {\n        const revShift = this._width - shift - 2;\n        this._bitrev[j] |= ((j >>> shift) & 3) << revShift;\n      }\n    }\n  }\n\n  /**\n   * Create a complex number array with size `2 * size`\n   *\n   * @returns {Float64Array} A complex number array with size `2 * size`\n   */\n  createComplexArray() {\n    return new Float64Array(this._csize);\n  }\n\n  /**\n   * Converts a complex number representation stored in a Float64Array to an array of real numbers.\n   *\n   * @param {Float64Array} complex The complex number representation to be converted.\n   * @param {number[]} [storage] An optional array to store the result in.\n   * @returns {number[]} An array of real numbers representing the input complex number representation.\n   */\n  fromComplexArray(complex: Float64Array, storage?: number[]) {\n    const res = storage || new Array(complex.length >>> 1);\n    for (let i = 0; i < complex.length; i += 2) res[i >>> 1] = complex[i];\n    return res;\n  }\n\n  /**\n   * Convert a real-valued input array to a complex-valued output array.\n   * @param {Float64Array} input The real-valued input array.\n   * @param {Float64Array} [storage] Optional buffer to store the output array.\n   * @returns {Float64Array} The complex-valued output array.\n   */\n  toComplexArray(input: number[], storage?: Float64Array) {\n    const res = storage || this.createComplexArray();\n    for (let i = 0; i < res.length; i += 2) {\n      res[i] = input[i >>> 1];\n      res[i + 1] = 0;\n    }\n    return res;\n  }\n\n  /**\n   * Performs a Fast Fourier Transform (FFT) on the given input data and stores the result in the output buffer.\n   *\n   * @param {Float64Array} out The output buffer to store the result.\n   * @param {Float64Array} data The input data to transform.\n   *\n   * @throws {Error} Input and output buffers must be different.\n   *\n   * @returns {void}\n   */\n  transform(out: Float64Array, data: Float64Array) {\n    if (out === data) throw new Error('Input and output buffers must be different');\n\n    this._transform4(out, data, 1 /* DONE */);\n  }\n\n  /**\n   * Performs a real-valued forward FFT on the given input buffer and stores the result in the given output buffer.\n   * The input buffer must contain real values only, while the output buffer will contain complex values. The input and\n   * output buffers must be different.\n   *\n   * @param {Float64Array} out The output buffer.\n   * @param {Float64Array} data The input buffer containing real values.\n   *\n   * @throws {Error} If the input and output buffers are the same.\n   */\n  realTransform(out: Float64Array, data: Float64Array) {\n    if (out === data) throw new Error('Input and output buffers must be different');\n\n    this._realTransform4(out, data, 1 /* DONE */);\n  }\n\n  /**\n   * Performs an inverse FFT transformation on the given `data` array, and stores the result in `out`.\n   * The `out` array must be a different buffer than the `data` array. The `out` array will contain the\n   * result of the transformation. The `data` array will not be modified.\n   *\n   * @param {Float64Array} out The output buffer for the transformed data.\n   * @param {Float64Array} data The input data to transform.\n   * @throws {Error} If `out` and `data` refer to the same buffer.\n   * @returns {void}\n   */\n  inverseTransform(out: Float64Array, data: Float64Array) {\n    if (out === data) throw new Error('Input and output buffers must be different');\n\n    this._transform4(out, data, -1 /* DONE */);\n    for (let i = 0; i < out.length; ++i) out[i] /= this.size;\n  }\n\n  /**\n   * Performs a radix-4 implementation of a discrete Fourier transform on a given set of data.\n   *\n   * @param {Float64Array} out The output buffer for the transformed data.\n   * @param {Float64Array} data The input buffer of data to be transformed.\n   * @param {number} inv A scaling factor to apply to the transform.\n   * @returns {void}\n   */\n  _transform4(out: Float64Array, data: Float64Array, inv: number) {\n    // radix-4 implementation\n\n    const size = this._csize;\n\n    // Initial step (permute and transform)\n    const width = this._width;\n    let step = 1 << width;\n    let len = (size / step) << 1;\n\n    let outOff;\n    let t;\n    const bitrev = this._bitrev;\n    if (len === 4) {\n      for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {\n        const off = bitrev[t];\n        this._singleTransform2(data, out, outOff, off, step);\n      }\n    } else {\n      // len === 8\n      for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {\n        const off = bitrev[t];\n        this._singleTransform4(data, out, outOff, off, step, inv);\n      }\n    }\n\n    // Loop through steps in decreasing order\n    const table = this.table;\n    for (step >>= 2; step >= 2; step >>= 2) {\n      len = (size / step) << 1;\n      const quarterLen = len >>> 2;\n\n      // Loop through offsets in the data\n      for (outOff = 0; outOff < size; outOff += len) {\n        // Full case\n        const limit = outOff + quarterLen - 1;\n        for (let i = outOff, k = 0; i < limit; i += 2, k += step) {\n          const A = i;\n          const B = A + quarterLen;\n          const C = B + quarterLen;\n          const D = C + quarterLen;\n\n          // Original values\n          const Ar = out[A];\n          const Ai = out[A + 1];\n          const Br = out[B];\n          const Bi = out[B + 1];\n          const Cr = out[C];\n          const Ci = out[C + 1];\n          const Dr = out[D];\n          const Di = out[D + 1];\n\n          const tableBr = table[k];\n          const tableBi = inv * table[k + 1];\n          const MBr = Br * tableBr - Bi * tableBi;\n          const MBi = Br * tableBi + Bi * tableBr;\n\n          const tableCr = table[2 * k];\n          const tableCi = inv * table[2 * k + 1];\n          const MCr = Cr * tableCr - Ci * tableCi;\n          const MCi = Cr * tableCi + Ci * tableCr;\n\n          const tableDr = table[3 * k];\n          const tableDi = inv * table[3 * k + 1];\n          const MDr = Dr * tableDr - Di * tableDi;\n          const MDi = Dr * tableDi + Di * tableDr;\n\n          // Pre-Final values\n          const T0r = Ar + MCr;\n          const T0i = Ai + MCi;\n          const T1r = Ar - MCr;\n          const T1i = Ai - MCi;\n          const T2r = MBr + MDr;\n          const T2i = MBi + MDi;\n          const T3r = inv * (MBr - MDr);\n          const T3i = inv * (MBi - MDi);\n\n          // Final values\n          out[A] = T0r + T2r;\n          out[A + 1] = T0i + T2i;\n          out[B] = T1r + T3i;\n          out[B + 1] = T1i - T3r;\n          out[C] = T0r - T2r;\n          out[C + 1] = T0i - T2i;\n          out[D] = T1r - T3i;\n          out[D + 1] = T1i + T3r;\n        }\n      }\n    }\n  }\n\n  /**\n   * Performs a radix-2 implementation of a discrete Fourier transform on a given set of data.\n   *\n   * @param {Float64Array} data The input buffer of data to be transformed.\n   * @param {Float64Array} out The output buffer for the transformed data.\n   * @param {number} outOff The offset at which to write the output data.\n   * @param {number} off The offset at which to begin reading the input data.\n   * @param {number} step The step size for indexing the input data.\n   * @returns {void}\n   */\n  _singleTransform2(data: Float64Array, out: Float64Array, outOff: number, off: number, step: number) {\n    // radix-2 implementation\n    // NOTE: Only called for len=4\n\n    const evenR = data[off];\n    const evenI = data[off + 1];\n    const oddR = data[off + step];\n    const oddI = data[off + step + 1];\n\n    out[outOff] = evenR + oddR;\n    out[outOff + 1] = evenI + oddI;\n    out[outOff + 2] = evenR - oddR;\n    out[outOff + 3] = evenI - oddI;\n  }\n\n  /**\n   * Performs radix-4 transformation on input data of length 8\n   *\n   * @param {Float64Array} data Input data array of length 8\n   * @param {Float64Array} out Output data array of length 8\n   * @param {number} outOff Index of output array to start writing from\n   * @param {number} off Index of input array to start reading from\n   * @param {number} step Step size between elements in input array\n   * @param {number} inv Scaling factor for inverse transform\n   *\n   * @returns {void}\n   */\n  _singleTransform4(data: Float64Array, out: Float64Array, outOff: number, off: number, step: number, inv: number) {\n    // radix-4\n    // NOTE: Only called for len=8\n    const step2 = step * 2;\n    const step3 = step * 3;\n\n    // Original values\n    const Ar = data[off];\n    const Ai = data[off + 1];\n    const Br = data[off + step];\n    const Bi = data[off + step + 1];\n    const Cr = data[off + step2];\n    const Ci = data[off + step2 + 1];\n    const Dr = data[off + step3];\n    const Di = data[off + step3 + 1];\n\n    // Pre-Final values\n    const T0r = Ar + Cr;\n    const T0i = Ai + Ci;\n    const T1r = Ar - Cr;\n    const T1i = Ai - Ci;\n    const T2r = Br + Dr;\n    const T2i = Bi + Di;\n    const T3r = inv * (Br - Dr);\n    const T3i = inv * (Bi - Di);\n\n    // Final values\n    out[outOff] = T0r + T2r;\n    out[outOff + 1] = T0i + T2i;\n    out[outOff + 2] = T1r + T3i;\n    out[outOff + 3] = T1i - T3r;\n    out[outOff + 4] = T0r - T2r;\n    out[outOff + 5] = T0i - T2i;\n    out[outOff + 6] = T1r - T3i;\n    out[outOff + 7] = T1i + T3r;\n  }\n\n  /**\n   * Real input radix-4 implementation\n   * @param {Float64Array} out Output array for the transformed data\n   * @param {Float64Array} data Input array of real data to be transformed\n   * @param {number} inv The scale factor used to normalize the inverse transform\n   */\n  _realTransform4(out: Float64Array, data: Float64Array, inv: number) {\n    // Real input radix-4 implementation\n    const size = this._csize;\n\n    // Initial step (permute and transform)\n    const width = this._width;\n    let step = 1 << width;\n    let len = (size / step) << 1;\n\n    let outOff;\n    let t;\n    const bitrev = this._bitrev;\n    if (len === 4) {\n      for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {\n        const off = bitrev[t];\n        this._singleRealTransform2(data, out, outOff, off >>> 1, step >>> 1);\n      }\n    } else {\n      // len === 8\n      for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {\n        const off = bitrev[t];\n        this._singleRealTransform4(data, out, outOff, off >>> 1, step >>> 1, inv);\n      }\n    }\n\n    // Loop through steps in decreasing order\n    const table = this.table;\n    for (step >>= 2; step >= 2; step >>= 2) {\n      len = (size / step) << 1;\n      const halfLen = len >>> 1;\n      const quarterLen = halfLen >>> 1;\n      const hquarterLen = quarterLen >>> 1;\n\n      // Loop through offsets in the data\n      for (outOff = 0; outOff < size; outOff += len) {\n        for (let i = 0, k = 0; i <= hquarterLen; i += 2, k += step) {\n          const A = outOff + i;\n          const B = A + quarterLen;\n          const C = B + quarterLen;\n          const D = C + quarterLen;\n\n          // Original values\n          const Ar = out[A];\n          const Ai = out[A + 1];\n          const Br = out[B];\n          const Bi = out[B + 1];\n          const Cr = out[C];\n          const Ci = out[C + 1];\n          const Dr = out[D];\n          const Di = out[D + 1];\n\n          // Middle values\n          const MAr = Ar;\n          const MAi = Ai;\n\n          const tableBr = table[k];\n          const tableBi = inv * table[k + 1];\n          const MBr = Br * tableBr - Bi * tableBi;\n          const MBi = Br * tableBi + Bi * tableBr;\n\n          const tableCr = table[2 * k];\n          const tableCi = inv * table[2 * k + 1];\n          const MCr = Cr * tableCr - Ci * tableCi;\n          const MCi = Cr * tableCi + Ci * tableCr;\n\n          const tableDr = table[3 * k];\n          const tableDi = inv * table[3 * k + 1];\n          const MDr = Dr * tableDr - Di * tableDi;\n          const MDi = Dr * tableDi + Di * tableDr;\n\n          // Pre-Final values\n          const T0r = MAr + MCr;\n          const T0i = MAi + MCi;\n          const T1r = MAr - MCr;\n          const T1i = MAi - MCi;\n          const T2r = MBr + MDr;\n          const T2i = MBi + MDi;\n          const T3r = inv * (MBr - MDr);\n          const T3i = inv * (MBi - MDi);\n\n          // Final values\n          out[A] = T0r + T2r;\n          out[A + 1] = T0i + T2i;\n          out[B] = T1r + T3i;\n          out[B + 1] = T1i - T3r;\n\n          // Output final middle point\n          if (i === 0) {\n            out[C] = T0r - T2r;\n            out[C + 1] = T0i - T2i;\n            continue;\n          }\n\n          // Do not overwrite ourselves\n          if (i === hquarterLen) continue;\n\n          const SA = outOff + quarterLen - i;\n          const SB = outOff + halfLen - i;\n\n          out[SA] = T1r - inv * T3i;\n          out[SA + 1] = -T1i - inv * T3r;\n          out[SB] = T0r - inv * T2r;\n          out[SB + 1] = -T0i + inv * T2i;\n        }\n      }\n    }\n\n    // Complete the spectrum by adding its mirrored negative frequency components.\n    const half = size >>> 1;\n    for (let i = 2; i < half; i += 2) {\n      out[size - i] = out[i];\n      out[size - i + 1] = -out[i + 1];\n    }\n  }\n\n  /**\n   * Performs a single real input radix-2 transformation on the provided data\n   *\n   * @param {Float64Array} data The input data array\n   * @param {Float64Array} out The output data array\n   * @param {number} outOff The output offset\n   * @param {number} off The input offset\n   * @param {number} step The step\n   *\n   * @returns {void}\n   */\n  _singleRealTransform2(data: Float64Array, out: Float64Array, outOff: number, off: number, step: number) {\n    // radix-2 implementation\n    // NOTE: Only called for len=4\n\n    const evenR = data[off];\n    const oddR = data[off + step];\n\n    out[outOff] = evenR + oddR;\n    out[outOff + 1] = 0;\n    out[outOff + 2] = evenR - oddR;\n    out[outOff + 3] = 0;\n  }\n\n  /**\n   * Computes a single real-valued transform using radix-4 algorithm.\n   * This method is only called for len=8.\n   *\n   * @param {Float64Array} data The input data array.\n   * @param {Float64Array} out The output data array.\n   * @param {number} outOff The offset into the output array.\n   * @param {number} off The offset into the input array.\n   * @param {number} step The step size for the input array.\n   * @param {number} inv The value of inverse.\n   */\n  _singleRealTransform4(data: Float64Array, out: Float64Array, outOff: number, off: number, step: number, inv: number) {\n    // radix-4\n    // NOTE: Only called for len=8\n    const step2 = step * 2;\n    const step3 = step * 3;\n\n    // Original values\n    const Ar = data[off];\n    const Br = data[off + step];\n    const Cr = data[off + step2];\n    const Dr = data[off + step3];\n\n    // Pre-Final values\n    const T0r = Ar + Cr;\n    const T1r = Ar - Cr;\n    const T2r = Br + Dr;\n    const T3r = inv * (Br - Dr);\n\n    // Final values\n    out[outOff] = T0r + T2r;\n    out[outOff + 1] = 0;\n    out[outOff + 2] = T1r;\n    out[outOff + 3] = -T3r;\n    out[outOff + 4] = T0r - T2r;\n    out[outOff + 5] = 0;\n    out[outOff + 6] = T1r;\n    out[outOff + 7] = T3r;\n  }\n}\n\n/**\n * NP2FFT class provides functionality for performing Fast Fourier Transform on arrays\n * which are not a power of two in length. In such cases, the chirp-z transform is used.\n *\n * For more information, see: https://math.stackexchange.com/questions/77118/non-power-of-2-ffts/77156#77156\n */\nclass NP2FFT {\n  private _f: P2FFT;\n  private bufferSize: number;\n  private _a: number;\n  private _chirpBuffer: Float64Array;\n  private _buffer1: Float64Array;\n  private _buffer2: Float64Array;\n  private _outBuffer1: Float64Array;\n  private _outBuffer2: Float64Array;\n  private _slicedChirpBuffer: Float64Array;\n\n  constructor(fft_length: number) {\n    // Helper variables\n    const a = 2 * (fft_length - 1);\n    const b = 2 * (2 * fft_length - 1);\n    const nextP2 = 2 ** Math.ceil(Math.log2(b));\n    this.bufferSize = nextP2;\n    this._a = a;\n\n    // Define buffers\n    // Compute chirp for transform\n    const chirp = new Float64Array(b);\n    const ichirp = new Float64Array(nextP2);\n    this._chirpBuffer = new Float64Array(nextP2);\n    this._buffer1 = new Float64Array(nextP2);\n    this._buffer2 = new Float64Array(nextP2);\n    this._outBuffer1 = new Float64Array(nextP2);\n    this._outBuffer2 = new Float64Array(nextP2);\n\n    // Compute complex exponentiation\n    const theta = (-2 * Math.PI) / fft_length;\n    const baseR = Math.cos(theta);\n    const baseI = Math.sin(theta);\n\n    // Precompute helper for chirp-z transform\n    for (let i = 0; i < b >> 1; ++i) {\n      // Compute complex power:\n      const e = (i + 1 - fft_length) ** 2 / 2.0;\n\n      // Compute the modulus and argument of the result\n      const result_mod = Math.sqrt(baseR ** 2 + baseI ** 2) ** e;\n      const result_arg = e * Math.atan2(baseI, baseR);\n\n      // Convert the result back to rectangular form\n      // and assign to chirp and ichirp\n      const i2 = 2 * i;\n      chirp[i2] = result_mod * Math.cos(result_arg);\n      chirp[i2 + 1] = result_mod * Math.sin(result_arg);\n\n      // conjugate\n      ichirp[i2] = chirp[i2];\n      ichirp[i2 + 1] = -chirp[i2 + 1];\n    }\n    this._slicedChirpBuffer = chirp.subarray(a, b);\n\n    // create object to perform Fast Fourier Transforms\n    // with `nextP2` complex numbers\n    this._f = new P2FFT(nextP2 >> 1);\n    this._f.transform(this._chirpBuffer, ichirp);\n  }\n\n  _transform(output: Float64Array, input: Float64Array, real: boolean) {\n    const ib1 = this._buffer1;\n    const ib2 = this._buffer2;\n    const ob2 = this._outBuffer1;\n    const ob3 = this._outBuffer2;\n    const cb = this._chirpBuffer;\n    const sb = this._slicedChirpBuffer;\n    const a = this._a;\n\n    if (real) {\n      // Real multiplication\n      for (let j = 0; j < sb.length; j += 2) {\n        const j2 = j + 1;\n        const j3 = j >> 1;\n\n        const a_real = input[j3];\n        ib1[j] = a_real * sb[j];\n        ib1[j2] = a_real * sb[j2];\n      }\n    } else {\n      // Complex multiplication\n      for (let j = 0; j < sb.length; j += 2) {\n        const j2 = j + 1;\n        ib1[j] = input[j] * sb[j] - input[j2] * sb[j2];\n        ib1[j2] = input[j] * sb[j2] + input[j2] * sb[j];\n      }\n    }\n    this._f.transform(ob2, ib1);\n\n    for (let j = 0; j < cb.length; j += 2) {\n      const j2 = j + 1;\n\n      ib2[j] = ob2[j] * cb[j] - ob2[j2] * cb[j2];\n      ib2[j2] = ob2[j] * cb[j2] + ob2[j2] * cb[j];\n    }\n    this._f.inverseTransform(ob3, ib2);\n\n    for (let j = 0; j < ob3.length; j += 2) {\n      const a_real = ob3[j + a];\n      const a_imag = ob3[j + a + 1];\n      const b_real = sb[j];\n      const b_imag = sb[j + 1];\n\n      output[j] = a_real * b_real - a_imag * b_imag;\n      output[j + 1] = a_real * b_imag + a_imag * b_real;\n    }\n  }\n\n  transform(output: Float64Array, input: Float64Array) {\n    this._transform(output, input, false);\n  }\n\n  realTransform(output: Float64Array, input: Float64Array) {\n    this._transform(output, input, true);\n  }\n\n  get size(): number {\n    return this.bufferSize;\n  }\n}\n\nexport class FFT {\n  fft_length: number;\n  isPowerOfTwo: boolean;\n  fft: P2FFT | NP2FFT;\n  outputBufferSize: number;\n\n  constructor(fft_length: number) {\n    this.fft_length = fft_length;\n    this.isPowerOfTwo = isPowerOfTwo(fft_length);\n    if (this.isPowerOfTwo) {\n      this.fft = new P2FFT(fft_length);\n      this.outputBufferSize = 2 * fft_length;\n    } else {\n      this.fft = new NP2FFT(fft_length);\n      this.outputBufferSize = this.fft.size;\n    }\n  }\n\n  realTransform(out: Float64Array, input: Float64Array) {\n    this.fft.realTransform(out, input);\n  }\n\n  transform(out: Float64Array, input: Float64Array) {\n    this.fft.transform(out, input);\n  }\n}\n\n/**\n * Performs median filter on the provided data. Padding is done by mirroring the data.\n * @param {AnyTypedArray} data The input array\n * @param {number} windowSize The window size\n */\nexport function medianFilter(data: AnyTypedArray, windowSize: number) {\n  if (windowSize % 2 === 0 || windowSize <= 0) {\n    throw new Error('Window size must be a positive odd number');\n  }\n\n  // @ts-ignore\n  const outputArray = new data.constructor(data.length);\n\n  // @ts-ignore\n  const buffer = new data.constructor(windowSize); // Reusable array for storing values\n\n  const halfWindowSize = Math.floor(windowSize / 2);\n\n  for (let i = 0; i < data.length; ++i) {\n    let valuesIndex = 0;\n\n    for (let j = -halfWindowSize; j <= halfWindowSize; ++j) {\n      let index = i + j;\n      if (index < 0) {\n        index = Math.abs(index);\n      } else if (index >= data.length) {\n        index = 2 * (data.length - 1) - index;\n      }\n\n      buffer[valuesIndex++] = data[index];\n    }\n\n    buffer.sort();\n    outputArray[i] = buffer[halfWindowSize];\n  }\n\n  return outputArray;\n}\n\n/**\n * Helper function to round a number to a given number of decimals\n * @param {number} num The number to round\n * @param {number} decimals The number of decimals\n * @returns {number} The rounded number\n */\nexport function round(num: number, decimals: number) {\n  const pow = Math.pow(10, decimals);\n  return Math.round(num * pow) / pow;\n}\n\n/**\n * Helper function to round a number to the nearest integer, with ties rounded to the nearest even number.\n * Also known as \"bankers' rounding\". This is the default rounding mode in python. For example:\n * 1.5 rounds to 2 and 2.5 rounds to 2.\n *\n * @param {number} x The number to round\n * @returns {number} The rounded number\n */\nexport function bankers_round(x: number) {\n  const r = Math.round(x);\n  const br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r - 1) : r;\n  return br;\n}\n\n/**\n * Measures similarity between two temporal sequences (e.g., input audio and output tokens\n * to generate token-level timestamps).\n * @param {number[][]} matrix\n * @returns {number[][]}\n */\nexport function dynamic_time_warping(matrix: number[][]) {\n  const output_length = matrix.length;\n  const input_length = matrix[0].length;\n\n  const outputShape = [output_length + 1, input_length + 1];\n\n  const cost = Array.from({ length: outputShape[0] }, () => Array(outputShape[1]).fill(Infinity));\n  cost[0][0] = 0;\n\n  const trace = Array.from({ length: outputShape[0] }, () => Array(outputShape[1]).fill(-1));\n\n  for (let j = 1; j < outputShape[1]; ++j) {\n    for (let i = 1; i < outputShape[0]; ++i) {\n      const c0 = cost[i - 1][j - 1];\n      const c1 = cost[i - 1][j];\n      const c2 = cost[i][j - 1];\n\n      let c, t;\n      if (c0 < c1 && c0 < c2) {\n        c = c0;\n        t = 0;\n      } else if (c1 < c0 && c1 < c2) {\n        c = c1;\n        t = 1;\n      } else {\n        c = c2;\n        t = 2;\n      }\n      cost[i][j] = matrix[i - 1][j - 1] + c;\n      trace[i][j] = t;\n    }\n  }\n\n  for (let i = 0; i < outputShape[1]; ++i) {\n    // trace[0, :] = 2\n    trace[0][i] = 2;\n  }\n  for (let i = 0; i < outputShape[0]; ++i) {\n    // trace[:, 0] = 1\n    trace[i][0] = 1;\n  }\n\n  // backtrace\n  let i = output_length;\n  let j = input_length;\n  let text_indices = [];\n  let time_indices = [];\n  while (i > 0 || j > 0) {\n    text_indices.push(i - 1);\n    time_indices.push(j - 1);\n\n    switch (trace[i][j]) {\n      case 0:\n        --i;\n        --j;\n        break;\n      case 1:\n        --i;\n        break;\n      case 2:\n        --j;\n        break;\n      default:\n        throw new Error(\n          `Internal error in dynamic time warping. Unexpected trace[${i}, ${j}]. Please file a bug report.`,\n        );\n    }\n  }\n\n  text_indices.reverse();\n  time_indices.reverse();\n\n  return [text_indices, time_indices];\n}\n","/**\n * @file Handler file for choosing the correct version of ONNX Runtime, based on the environment.\n * Ideally, we could import the `onnxruntime-web` and `onnxruntime-node` packages only when needed,\n * but dynamic imports don't seem to work with the current webpack version and/or configuration.\n * This is possibly due to the experimental nature of top-level await statements.\n * So, we just import both packages, and use the appropriate one based on the environment:\n *   - When running in node, we use `onnxruntime-node`.\n *   - When running in the browser, we use `onnxruntime-web` (`onnxruntime-node` is not bundled).\n *\n * This module is not directly exported, but can be accessed through the environment variables:\n * ```javascript\n * import { env } from '@huggingface/transformers';\n * console.log(env.backends.onnx);\n * ```\n *\n * @module backends/onnx\n */\n\nimport { env, apis } from '../env';\n\n// NOTE: Import order matters here. We need to import `onnxruntime-node` before `onnxruntime-web`.\n// In either case, we select the default export if it exists, otherwise we use the named export.\nimport * as ONNX from 'onnxruntime-web';\nexport { Tensor } from 'onnxruntime-common';\n\n/**\n * @typedef {import('onnxruntime-common').InferenceSession.ExecutionProviderConfig} ONNXExecutionProviders\n */\n\n/** @type {Record<import(\"../utils/devices.js\").DeviceType, ONNXExecutionProviders>} */\nconst DEVICE_TO_EXECUTION_PROVIDER_MAPPING = Object.freeze({\n  auto: null, // Auto-detect based on device and environment\n  gpu: null, // Auto-detect GPU\n  cpu: 'cpu', // CPU\n  wasm: 'wasm', // WebAssembly\n  webgpu: 'webgpu', // WebGPU\n  cuda: 'cuda', // CUDA\n  dml: 'dml', // DirectML\n\n  webnn: { name: 'webnn', deviceType: 'cpu' }, // WebNN (default)\n  'webnn-npu': { name: 'webnn', deviceType: 'npu' }, // WebNN NPU\n  'webnn-gpu': { name: 'webnn', deviceType: 'gpu' }, // WebNN GPU\n  'webnn-cpu': { name: 'webnn', deviceType: 'cpu' }, // WebNN CPU\n});\n\n/**\n * The list of supported devices, sorted by priority/performance.\n * @type {import(\"../utils/devices.js\").DeviceType[]}\n */\nconst supportedDevices: string[] = [];\n\n/** @type {ONNXExecutionProviders[]} */\nlet defaultDevices: string[] = [];\n\n\n// Then add WebNN support\nif (apis.IS_WEBNN_AVAILABLE) {\n  supportedDevices.push('webnn-gpu', 'webnn-cpu');\n}\n\n// Add WebGPU as an option if available\nif (apis.IS_WEBGPU_AVAILABLE) {\n  // Add WASM as fallback when WebGPU fails\n  supportedDevices.push('wasm', 'webgpu');\n}\n\n// Remove the previous \"Always keep WASM as fallback\" section since we've integrated it above\nif (defaultDevices.length === 0) {\n  defaultDevices = ['wasm'];\n}\n\nconst InferenceSession = ONNX.InferenceSession;\n\n/**\n * Map a device to the execution providers to use for the given device.\n * @param {import(\"../utils/devices.js\").DeviceType|\"auto\"|null} [device=null] (Optional) The device to run the inference on.\n * @returns {ONNXExecutionProviders[]} The execution providers to use for the given device.\n */\nexport function deviceToExecutionProviders(device = null) {\n  // Use the default execution providers if the user hasn't specified anything\n  if (!device) return defaultDevices;\n\n  // Handle overloaded cases\n  switch (device) {\n    case 'auto':\n      return supportedDevices;\n    case 'gpu':\n      return supportedDevices.filter((x) => ['webgpu', 'cuda', 'dml', 'webnn-gpu'].includes(x));\n  }\n\n  if (supportedDevices.includes(device)) {\n    return [DEVICE_TO_EXECUTION_PROVIDER_MAPPING[device] ?? device];\n  }\n\n  throw new Error(`Unsupported device: \"${device}\". Should be one of: ${supportedDevices.join(', ')}.`);\n}\n\n/**\n * To prevent multiple calls to `initWasm()`, we store the first call in a Promise\n * that is resolved when the first InferenceSession is created. Subsequent calls\n * will wait for this Promise to resolve before creating their own InferenceSession.\n * @type {Promise<any>|null}\n */\nlet wasmInitPromise: Promise<any> | null = null;\n\n/**\n * Create an ONNX inference session.\n * @param {Uint8Array} buffer The ONNX model buffer.\n * @param {import('onnxruntime-common').InferenceSession.SessionOptions} session_options ONNX inference session options.\n * @param {Object} session_config ONNX inference session configuration.\n * @returns {Promise<import('onnxruntime-common').InferenceSession & { config: Object}>} The ONNX inference session.\n */\nexport async function createInferenceSession(\n  buffer: Uint8Array,\n  session_options: any,\n  session_config: any\n) {\n  if (wasmInitPromise) {\n    // A previous session has already initialized the WASM runtime\n    // so we wait for it to resolve before creating this new session.\n    await wasmInitPromise;\n  }\n\n  const sessionPromise = InferenceSession.create(buffer, session_options);\n  wasmInitPromise ??= sessionPromise;\n  const session = await sessionPromise;\n  (session as any).config = session_config;\n  return session;\n}\n\n/**\n * Check if an object is an ONNX tensor.\n * @param {any} x The object to check\n * @returns {boolean} Whether the object is an ONNX tensor.\n */\nexport function isONNXTensor(x: any) {\n  return x instanceof ONNX.Tensor;\n}\n\n/** @type {import('onnxruntime-common').Env} */\n// @ts-ignore\nconst ONNX_ENV = ONNX?.env;\nif (ONNX_ENV?.wasm) {\n  // Initialize wasm backend with suitable default settings.\n\n  // (Optional) Set path to wasm files. This is needed when running in a web worker.\n  // https://onnxruntime.ai/docs/api/js/interfaces/Env.WebAssemblyFlags.html#wasmPaths\n  // We use remote wasm files by default to make it easier for newer users.\n  // In practice, users should probably self-host the necessary .wasm files.\n\n  ONNX_ENV.wasm.wasmPaths = {\n    wasm: `https://cdn.jsdelivr.net/npm/@huggingface/transformers@${env.version}/dist/ort-wasm-simd-threaded.jsep.wasm`,\n    mjs: `https://cdn.jsdelivr.net/npm/@huggingface/transformers@${env.version}/dist/ort-wasm-simd-threaded.jsep.mjs`,\n  };\n  // https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.2.4/dist/ort-wasm-simd-threaded.jsep.wasm\n  // console.log('ONNX_ENV.wasm.wasmPaths', ONNX_ENV.wasm.wasmPaths);\n  // TODO: Add support for loading WASM files from cached buffer when we upgrade to onnxruntime-web@1.19.0\n  // https://github.com/microsoft/onnxruntime/pull/21534\n\n  // Users may wish to proxy the WASM backend to prevent the UI from freezing,\n  // However, this is not necessary when using WebGPU, so we default to false.\n  ONNX_ENV.wasm.proxy = false;\n\n  // Disable threading to avoid potential issues\n  ONNX_ENV.wasm.numThreads = 1;\n  \n  // https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated\n  if (typeof crossOriginIsolated === 'undefined' || !crossOriginIsolated) {\n    ONNX_ENV.wasm.numThreads = 1;\n  }\n}\n\nif (ONNX_ENV?.webgpu) {\n  // console.log('ONNX_ENV.webgpu', ONNX_ENV.webgpu);\n  ONNX_ENV.webgpu.powerPreference = 'high-performance';\n}\n\n/**\n * Check if ONNX's WASM backend is being proxied.\n * @returns {boolean} Whether ONNX's WASM backend is being proxied.\n */\nexport function isONNXProxy() {\n  // TODO: Update this when allowing non-WASM backends.\n  return ONNX_ENV?.wasm?.proxy;\n}\n\n// Expose ONNX environment variables to `env.backends.onnx`\nenv.backends.onnx = ONNX_ENV;\n","import { createInferenceSession, isONNXProxy } from '../backends/onnx';\nimport { Tensor } from '../utils/tensor';\n\n/**\n * Asynchronously creates a wrapper function for running an ONNX inference session.\n *\n * @param {number[]} session_bytes The session data in bytes.\n * @param {import('onnxruntime-common').InferenceSession.SessionOptions} session_options The options for the ONNX session.\n * @template {string | [string] | string[]} T\n * @param {T} names The name(s) of the output tensor(s).\n *\n * @returns {Promise<function(Record<string, Tensor>): Promise<T extends string ? Tensor : T extends string[] ? { [K in keyof T]: Tensor } : never>>}\n * The wrapper function for running the ONNX inference session.\n */\nconst wrap = async (\n  session_bytes: number[],\n  session_options: import('onnxruntime-common').InferenceSession.SessionOptions,\n  names: string | string[],\n) => {\n  const session = await createInferenceSession(new Uint8Array(session_bytes), session_options, {});\n\n  let chain = Promise.resolve();\n\n  return /** @type {any} */ async (/** @type {Record<string, Tensor>} */ inputs: Record<string, Tensor>) => {\n    const proxied = isONNXProxy();\n    const ortFeed = Object.fromEntries(\n      Object.entries(inputs).map(([k, v]) => [k, (proxied ? v.clone() : v).ort_tensor]),\n    );\n    // When running in-browser via WASM, we need to chain calls to session.run to avoid \"Error: Session already started\"\n    const outputs = await (chain.then(() => session.run(ortFeed as any)));\n\n    if (Array.isArray(names)) {\n      return names.map((n) => new Tensor(outputs[n]));\n    } else {\n      return new Tensor(outputs[/** @type {string} */ names]);\n    }\n  };\n};\n\n// In-memory registry of initialized ONNX operators\nexport class TensorOpRegistry {\n  private static _nearest_interpolate_4d: any;\n  private static _bilinear_interpolate_4d: any;\n  private static _bicubic_interpolate_4d: any;\n  private static _matmul: any;\n  private static _stft: any;\n  private static _rfft: any;\n  private static _top_k: any;\n  private static _slice: any;\n\n  static session_options = {\n    // TODO: Allow for multiple execution providers\n    // executionProviders: ['webgpu'],\n  };\n\n  static get nearest_interpolate_4d() {\n    if (!this._nearest_interpolate_4d) {\n      this._nearest_interpolate_4d = wrap(\n        [\n          8, 10, 18, 0, 58, 129, 1, 10, 41, 10, 1, 120, 10, 0, 10, 0, 10, 1, 115, 18, 1, 121, 34, 6, 82, 101, 115, 105,\n          122, 101, 42, 18, 10, 4, 109, 111, 100, 101, 34, 7, 110, 101, 97, 114, 101, 115, 116, 160, 1, 3, 18, 1, 114,\n          90, 31, 10, 1, 120, 18, 26, 10, 24, 8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10,\n          3, 18, 1, 119, 90, 15, 10, 1, 115, 18, 10, 10, 8, 8, 7, 18, 4, 10, 2, 8, 4, 98, 31, 10, 1, 121, 18, 26, 10,\n          24, 8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10, 3, 18, 1, 119, 66, 2, 16, 21,\n        ],\n        this.session_options,\n        'y',\n      );\n    }\n    return this._nearest_interpolate_4d;\n  }\n  static get bilinear_interpolate_4d() {\n    if (!this._bilinear_interpolate_4d) {\n      this._bilinear_interpolate_4d = wrap(\n        [\n          8, 9, 18, 0, 58, 128, 1, 10, 40, 10, 1, 120, 10, 0, 10, 0, 10, 1, 115, 18, 1, 121, 34, 6, 82, 101, 115, 105,\n          122, 101, 42, 17, 10, 4, 109, 111, 100, 101, 34, 6, 108, 105, 110, 101, 97, 114, 160, 1, 3, 18, 1, 114, 90,\n          31, 10, 1, 120, 18, 26, 10, 24, 8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10, 3,\n          18, 1, 119, 90, 15, 10, 1, 115, 18, 10, 10, 8, 8, 7, 18, 4, 10, 2, 8, 4, 98, 31, 10, 1, 121, 18, 26, 10, 24,\n          8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10, 3, 18, 1, 119, 66, 2, 16, 20,\n        ],\n        this.session_options,\n        'y',\n      );\n    }\n    return this._bilinear_interpolate_4d;\n  }\n\n  static get bicubic_interpolate_4d() {\n    if (!this._bicubic_interpolate_4d) {\n      this._bicubic_interpolate_4d = wrap(\n        [\n          8, 9, 18, 0, 58, 127, 10, 39, 10, 1, 120, 10, 0, 10, 0, 10, 1, 115, 18, 1, 121, 34, 6, 82, 101, 115, 105, 122,\n          101, 42, 16, 10, 4, 109, 111, 100, 101, 34, 5, 99, 117, 98, 105, 99, 160, 1, 3, 18, 1, 114, 90, 31, 10, 1,\n          120, 18, 26, 10, 24, 8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10, 3, 18, 1, 119,\n          90, 15, 10, 1, 115, 18, 10, 10, 8, 8, 7, 18, 4, 10, 2, 8, 4, 98, 31, 10, 1, 121, 18, 26, 10, 24, 8, 1, 18, 20,\n          10, 3, 18, 1, 98, 10, 3, 18, 1, 99, 10, 3, 18, 1, 104, 10, 3, 18, 1, 119, 66, 2, 16, 20,\n        ],\n        this.session_options,\n        'y',\n      );\n    }\n    return this._bicubic_interpolate_4d;\n  }\n\n  static get matmul() {\n    if (!this._matmul) {\n      this._matmul = wrap(\n        [\n          8, 9, 18, 0, 58, 55, 10, 17, 10, 1, 97, 10, 1, 98, 18, 1, 99, 34, 6, 77, 97, 116, 77, 117, 108, 18, 1, 114,\n          90, 9, 10, 1, 97, 18, 4, 10, 2, 8, 1, 90, 9, 10, 1, 98, 18, 4, 10, 2, 8, 1, 98, 9, 10, 1, 99, 18, 4, 10, 2, 8,\n          1, 66, 2, 16, 20,\n        ],\n        this.session_options,\n        'c',\n      );\n    }\n    return this._matmul;\n  }\n\n  static get stft() {\n    if (!this._stft) {\n      this._stft = wrap(\n        [\n          8, 7, 18, 0, 58, 148, 1, 10, 38, 10, 1, 115, 10, 1, 106, 10, 1, 119, 10, 1, 108, 18, 1, 111, 34, 4, 83, 84,\n          70, 84, 42, 15, 10, 8, 111, 110, 101, 115, 105, 100, 101, 100, 24, 1, 160, 1, 2, 18, 1, 115, 90, 26, 10, 1,\n          115, 18, 21, 10, 19, 8, 1, 18, 15, 10, 3, 18, 1, 98, 10, 3, 18, 1, 115, 10, 3, 18, 1, 99, 90, 11, 10, 1, 106,\n          18, 6, 10, 4, 8, 7, 18, 0, 90, 16, 10, 1, 119, 18, 11, 10, 9, 8, 1, 18, 5, 10, 3, 18, 1, 119, 90, 11, 10, 1,\n          108, 18, 6, 10, 4, 8, 7, 18, 0, 98, 31, 10, 1, 111, 18, 26, 10, 24, 8, 1, 18, 20, 10, 3, 18, 1, 98, 10, 3, 18,\n          1, 102, 10, 3, 18, 1, 100, 10, 3, 18, 1, 99, 66, 2, 16, 17,\n        ],\n        this.session_options,\n        'o',\n      );\n    }\n    return this._stft;\n  }\n\n  static get rfft() {\n    if (!this._rfft) {\n      this._rfft = wrap(\n        [\n          8, 9, 18, 0, 58, 97, 10, 33, 10, 1, 120, 10, 0, 10, 1, 97, 18, 1, 121, 34, 3, 68, 70, 84, 42, 15, 10, 8, 111,\n          110, 101, 115, 105, 100, 101, 100, 24, 1, 160, 1, 2, 18, 1, 100, 90, 21, 10, 1, 120, 18, 16, 10, 14, 8, 1, 18,\n          10, 10, 3, 18, 1, 115, 10, 3, 18, 1, 99, 90, 11, 10, 1, 97, 18, 6, 10, 4, 8, 7, 18, 0, 98, 21, 10, 1, 121, 18,\n          16, 10, 14, 8, 1, 18, 10, 10, 3, 18, 1, 115, 10, 3, 18, 1, 99, 66, 2, 16, 20,\n        ],\n        this.session_options,\n        'y',\n      );\n    }\n    return this._rfft;\n  }\n\n  static get top_k() {\n    if (!this._top_k) {\n      this._top_k = wrap(\n        [\n          8, 10, 18, 0, 58, 73, 10, 18, 10, 1, 120, 10, 1, 107, 18, 1, 118, 18, 1, 105, 34, 4, 84, 111, 112, 75, 18, 1,\n          116, 90, 9, 10, 1, 120, 18, 4, 10, 2, 8, 1, 90, 15, 10, 1, 107, 18, 10, 10, 8, 8, 7, 18, 4, 10, 2, 8, 1, 98,\n          9, 10, 1, 118, 18, 4, 10, 2, 8, 1, 98, 9, 10, 1, 105, 18, 4, 10, 2, 8, 7, 66, 2, 16, 21,\n        ],\n        this.session_options,\n        [/* Values */ 'v', /* Indices */ 'i'],\n      );\n    }\n    return this._top_k;\n  }\n\n  static get slice() {\n    if (!this._slice) {\n      this._slice = wrap(\n        [\n          8, 7, 18, 0, 58, 96, 10, 25, 10, 1, 120, 10, 1, 115, 10, 1, 101, 10, 1, 97, 10, 1, 116, 18, 1, 121, 34, 5, 83,\n          108, 105, 99, 101, 18, 1, 114, 90, 9, 10, 1, 120, 18, 4, 10, 2, 8, 1, 90, 9, 10, 1, 115, 18, 4, 10, 2, 8, 7,\n          90, 9, 10, 1, 101, 18, 4, 10, 2, 8, 7, 90, 9, 10, 1, 97, 18, 4, 10, 2, 8, 7, 90, 9, 10, 1, 116, 18, 4, 10, 2,\n          8, 7, 98, 9, 10, 1, 121, 18, 4, 10, 2, 8, 1, 66, 2, 16, 13,\n        ],\n        this.session_options,\n        'y',\n      );\n    }\n    return this._slice;\n  }\n}\n","/**\n * @file Helper module for `Tensor` processing.\n *\n * These functions and classes are only used internally,\n * meaning an end-user shouldn't need to access anything here.\n *\n * @module utils/tensor\n */\n\nimport { interpolate_data, max, min, permute_data } from './maths';\n\nimport { Tensor as ONNXTensor, isONNXTensor } from '../backends/onnx.js';\n\nimport { TensorOpRegistry } from '../ops/registry.js';\n\ntype TypedArray =\n  | Int8Array\n  | Uint8Array\n  | Uint8ClampedArray\n  | Int16Array\n  | Uint16Array\n  | Int32Array\n  | Uint32Array\n  | Float32Array\n  | Float64Array\n  | BigInt64Array\n  | BigUint64Array;\n\ntype DataArray = TypedArray | any[];\n\nconst DataTypeMap = Object.freeze({\n  float32: Float32Array,\n  float16: Uint16Array,\n  float64: Float64Array,\n  string: Array, // string[]\n  int8: Int8Array,\n  uint8: Uint8Array,\n  int16: Int16Array,\n  uint16: Uint16Array,\n  int32: Int32Array,\n  uint32: Uint32Array,\n  int64: BigInt64Array,\n  uint64: BigUint64Array,\n  bool: Uint8Array,\n  uint4: Uint8Array,\n  int4: Int8Array,\n});\n\ntype DataType = keyof typeof DataTypeMap;\n\n/**\n * @typedef {keyof typeof DataTypeMap} DataType\n * @typedef {import('./maths.js').AnyTypedArray | any[]} DataArray\n */\n\nexport class Tensor {\n  [index: number]: Tensor; // Add numeric index signature\n\n  /** @type {number[]} Dimensions of the tensor. */\n  get dims() {\n    // @ts-ignore\n    return this.ort_tensor.dims;\n  }\n  set dims(value) {\n    // FIXME: ONNXTensor declares dims as readonly so one needs to use the constructor() if dims change.\n    // @ts-ignore\n    this.ort_tensor.dims = value;\n  }\n\n  /** @type {DataType} Type of the tensor. */\n  get type(): DataType {\n    return (this.ort_tensor as { type: DataType }).type;\n  }\n\n  /** @type {DataArray} The data stored in the tensor. */\n  get data(): DataArray {\n    return (this.ort_tensor as { data: DataArray }).data;\n  }\n\n  /** @type {number} The number of elements in the tensor. */\n  get size() {\n    return (this.ort_tensor as { size: number }).size;\n  }\n\n  /** @type {string} The location of the tensor data. */\n  get location() {\n    return (this.ort_tensor as { location: string }).location;\n  }\n\n  ort_tensor;\n\n  /**\n   * Create a new Tensor or copy an existing Tensor.\n   * @param {[DataType, DataArray, number[]]|[ONNXTensor]} args\n   */\n  constructor(...args: [DataType, DataArray, number[]] | [ONNXTensor]) {\n    if (isONNXTensor(args[0])) {\n      this.ort_tensor = /** @type {ONNXTensor} */ args[0];\n    } else {\n      // Add debugging\n      // console.log('Creating new tensor:', {\n      //   type: args[0],\n      //   dataLength: (args[1] as DataArray).length,\n      //   dims: args[2]\n      // });\n      \n      try {\n        this.ort_tensor = new ONNXTensor(\n          args[0] as keyof typeof DataTypeMap,\n          args[1] as Exclude<TypedArray, Uint8ClampedArray>,\n          args[2],\n        );\n      } catch (error) {\n        console.error('Failed to create ONNXTensor:', {\n          error,\n          type: args[0],\n          dataLength: (args[1] as DataArray).length,\n          dims: args[2]\n        });\n        throw error;\n      }\n    }\n\n    return new Proxy(this, {\n      get: (obj, key) => {\n        if (typeof key === 'string') {\n          let index = Number(key);\n          if (Number.isInteger(index)) {\n            // key is an integer (i.e., index)\n            return obj._getitem(index);\n          }\n        }\n        // @ts-ignore\n        return obj[key];\n      },\n      set: (obj, key, value) => {\n        // TODO allow setting of data\n\n        // @ts-ignore\n        return (obj[key] = value);\n      },\n    });\n  }\n\n  dispose() {\n    (this.ort_tensor as ONNXTensor).dispose();\n    // this.ort_tensor = undefined;\n  }\n\n  /**\n   * Returns an iterator object for iterating over the tensor data in row-major order.\n   * If the tensor has more than one dimension, the iterator will yield subarrays.\n   * @returns {Iterator} An iterator object for iterating over the tensor data in row-major order.\n   */\n  *[Symbol.iterator]() {\n    const [iterLength, ...iterDims] = this.dims;\n\n    if (iterDims.length > 0) {\n      const iterSize = iterDims.reduce((a: number, b: number) => a * b);\n      for (let i = 0; i < iterLength; ++i) {\n        yield this._subarray(i, iterSize, iterDims);\n      }\n    } else {\n      yield* this.data;\n    }\n  }\n\n  /**\n   * Index into a Tensor object.\n   * @param {number} index The index to access.\n   * @returns {Tensor} The data at the specified index.\n   */\n  _getitem(index: number) {\n    const [iterLength, ...iterDims] = this.dims;\n\n    index = safeIndex(index, iterLength);\n\n    if (iterDims.length > 0) {\n      const iterSize = iterDims.reduce((a: number, b: number) => a * b);\n      return this._subarray(index, iterSize, iterDims);\n    } else {\n      return new Tensor(this.type, [this.data[index]], iterDims);\n    }\n  }\n\n  /**\n   * @param {number|bigint} item The item to search for in the tensor\n   * @returns {number} The index of the first occurrence of item in the tensor data.\n   */\n  indexOf(item: number | bigint) {\n    const this_data = this.data;\n    for (let index = 0; index < this_data.length; ++index) {\n      // Note: == instead of === so we can match Ints with BigInts\n      if (this_data[index] == item) {\n        return index;\n      }\n    }\n    return -1;\n  }\n\n  /**\n   * @param {number} index\n   * @param {number} iterSize\n   * @param {any} iterDims\n   * @returns {Tensor}\n   */\n  _subarray(index: number, iterSize: number, iterDims: number[]) {\n    const o1 = index * iterSize;\n    const o2 = (index + 1) * iterSize;\n\n    // We use subarray if available (typed array), otherwise we use slice (normal array)\n    const data = 'subarray' in this.data ? this.data.subarray(o1, o2) : this.data.slice(o1, o2);\n    return new Tensor(this.type, data, iterDims);\n  }\n\n  /**\n   * Returns the value of this tensor as a standard JavaScript Number. This only works\n   * for tensors with one element. For other cases, see `Tensor.tolist()`.\n   * @returns {number|bigint} The value of this tensor as a standard JavaScript Number.\n   * @throws {Error} If the tensor has more than one element.\n   */\n  item() {\n    const this_data = this.data;\n    if (this_data.length !== 1) {\n      throw new Error(`a Tensor with ${this_data.length} elements cannot be converted to Scalar`);\n    }\n    return this_data[0];\n  }\n\n  /**\n   * Convert tensor data to a n-dimensional JS list\n   * @returns {Array}\n   */\n  tolist() {\n    return reshape(this.data, this.dims);\n  }\n\n  /**\n   * Return a new Tensor with the sigmoid function applied to each element.\n   * @returns {Tensor} The tensor with the sigmoid function applied.\n   */\n  sigmoid() {\n    return this.clone().sigmoid_();\n  }\n\n  /**\n   * Applies the sigmoid function to the tensor in place.\n   * @returns {Tensor} Returns `this`.\n   */\n  sigmoid_() {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] = 1 / (1 + Math.exp(-this_data[i]));\n    }\n    return this;\n  }\n\n  /**\n   * Return a new Tensor with a callback function applied to each element.\n   * @param {Function} callback - The function to apply to each element. It should take three arguments:\n   *                              the current element, its index, and the tensor's data array.\n   * @returns {Tensor} A new Tensor with the callback function applied to each element.\n   */\n  map(callback: Function) {\n    return this.clone().map_(callback);\n  }\n\n  /**\n   * Apply a callback function to each element of the tensor in place.\n   * @param {Function} callback - The function to apply to each element. It should take three arguments:\n   *                              the current element, its index, and the tensor's data array.\n   * @returns {Tensor} Returns `this`.\n   */\n  map_(callback: Function) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] = callback(this_data[i], i, this_data);\n    }\n    return this;\n  }\n\n  /**\n   * Return a new Tensor with every element multiplied by a constant.\n   * @param {number} val The value to multiply by.\n   * @returns {Tensor} The new tensor.\n   */\n  mul(val: number) {\n    return this.clone().mul_(val);\n  }\n\n  /**\n   * Multiply the tensor by a constant in place.\n   * @param {number} val The value to multiply by.\n   * @returns {Tensor} Returns `this`.\n   */\n  mul_(val: number) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] *= val;\n    }\n    return this;\n  }\n\n  /**\n   * Return a new Tensor with every element divided by a constant.\n   * @param {number} val The value to divide by.\n   * @returns {Tensor} The new tensor.\n   */\n  div(val: number) {\n    return this.clone().div_(val);\n  }\n\n  /**\n   * Divide the tensor by a constant in place.\n   * @param {number} val The value to divide by.\n   * @returns {Tensor} Returns `this`.\n   */\n  div_(val: number) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] /= val;\n    }\n    return this;\n  }\n\n  /**\n   * Return a new Tensor with every element added by a constant.\n   * @param {number} val The value to add by.\n   * @returns {Tensor} The new tensor.\n   */\n  add(val: number) {\n    return this.clone().add_(val);\n  }\n\n  /**\n   * Add the tensor by a constant in place.\n   * @param {number} val The value to add by.\n   * @returns {Tensor} Returns `this`.\n   */\n  add_(val: number) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] += val;\n    }\n    return this;\n  }\n\n  /**\n   * Return a new Tensor with every element subtracted by a constant.\n   * @param {number} val The value to subtract by.\n   * @returns {Tensor} The new tensor.\n   */\n  sub(val: number) {\n    return this.clone().sub_(val);\n  }\n\n  /**\n   * Subtract the tensor by a constant in place.\n   * @param {number} val The value to subtract by.\n   * @returns {Tensor} Returns `this`.\n   */\n  sub_(val: number) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] -= val;\n    }\n    return this;\n  }\n\n  /**\n   * Creates a deep copy of the current Tensor.\n   * @returns {Tensor} A new Tensor with the same type, data, and dimensions as the original.\n   */\n  clone() {\n    return new Tensor(this.type, this.data.slice(), this.dims.slice());\n  }\n\n  /**\n   * Performs a slice operation on the Tensor along specified dimensions.\n   *\n   * Consider a Tensor that has a dimension of [4, 7]:\n   * ```\n   * [ 1,  2,  3,  4,  5,  6,  7]\n   * [ 8,  9, 10, 11, 12, 13, 14]\n   * [15, 16, 17, 18, 19, 20, 21]\n   * [22, 23, 24, 25, 26, 27, 28]\n   * ```\n   * We can slice against the two dims of row and column, for instance in this\n   * case we can start at the second element, and return to the second last,\n   * like this:\n   * ```\n   * tensor.slice([1, -1], [1, -1]);\n   * ```\n   * which would return:\n   * ```\n   * [  9, 10, 11, 12, 13 ]\n   * [ 16, 17, 18, 19, 20 ]\n   * ```\n   *\n   * @param {...(number|number[]|null)} slices The slice specifications for each dimension.\n   * - If a number is given, then a single element is selected.\n   * - If an array of two numbers is given, then a range of elements [start, end (exclusive)] is selected.\n   * - If null is given, then the entire dimension is selected.\n   * @returns {Tensor} A new Tensor containing the selected elements.\n   * @throws {Error} If the slice input is invalid.\n   */\n  slice(...slices: (number | number[] | null)[]) {\n    // This allows for slicing with ranges and numbers\n    const newTensorDims = [];\n    const newOffsets = [];\n\n    // slices is an array of numbers or arrays of numbers\n    // e.g., slices = [0, [1, 3], null, [0, 3]]\n    for (let sliceIndex = 0; sliceIndex < this.dims.length; ++sliceIndex) {\n      let slice = slices[sliceIndex];\n\n      if (slice === null || slice === undefined) {\n        // null or undefined means take the whole dimension\n        newOffsets.push([0, this.dims[sliceIndex]]);\n        newTensorDims.push(this.dims[sliceIndex]);\n      } else if (typeof slice === 'number') {\n        slice = safeIndex(slice, this.dims[sliceIndex], sliceIndex);\n\n        // A number means take a single element\n        newOffsets.push([slice, slice + 1]);\n      } else if (Array.isArray(slice) && slice.length === 2) {\n        // An array of length 2 means take a range of elements\n        let [start, end] = slice;\n        start = start === null ? 0 : safeIndex(start, this.dims[sliceIndex], sliceIndex, false);\n        end = end === null ? this.dims[sliceIndex] : safeIndex(end, this.dims[sliceIndex], sliceIndex, false);\n\n        if (start > end) {\n          throw new Error(`Invalid slice: ${slice}`);\n        }\n\n        const offsets = [Math.max(start, 0), Math.min(end, this.dims[sliceIndex])];\n\n        newOffsets.push(offsets);\n        newTensorDims.push(offsets[1] - offsets[0]);\n      } else {\n        throw new Error(`Invalid slice: ${slice}`);\n      }\n    }\n\n    const newDims = newOffsets.map(([start, end]) => end - start);\n    const newBufferSize = newDims.reduce((a, b) => a * b);\n\n    const this_data = this.data;\n    // Allocate memory\n    // @ts-ignore\n    const data = new this_data.constructor(newBufferSize);\n\n    // Precompute strides\n    const stride = this.stride();\n\n    for (let i = 0; i < newBufferSize; ++i) {\n      let originalIndex = 0;\n      for (let j = newDims.length - 1, num = i; j >= 0; --j) {\n        const size = newDims[j];\n        originalIndex += ((num % size) + newOffsets[j][0]) * stride[j];\n        num = Math.floor(num / size);\n      }\n      data[i] = this_data[originalIndex];\n    }\n    return new Tensor(this.type, data, newTensorDims);\n  }\n\n  /**\n   * Return a permuted version of this Tensor, according to the provided dimensions.\n   * @param  {...number} dims Dimensions to permute.\n   * @returns {Tensor} The permuted tensor.\n   */\n  permute(...dims: number[]) {\n    return permute(this, dims);\n  }\n\n  // TODO: implement transpose. For now (backwards compatibility), it's just an alias for permute()\n  transpose(...dims: number[]) {\n    return this.permute(...dims);\n  }\n\n  /**\n   * Returns the sum of each row of the input tensor in the given dimension dim.\n   *\n   * @param {number} [dim=null] The dimension or dimensions to reduce. If `null`, all dimensions are reduced.\n   * @param {boolean} keepdim Whether the output tensor has `dim` retained or not.\n   * @returns The summed tensor\n   */\n  sum(dim: number | null = null, keepdim: boolean = false) {\n    return this.norm(1 as any, dim, keepdim);\n  }\n\n  /**\n   * Returns the matrix norm or vector norm of a given tensor.\n   * @param {number|string} [p='fro'] The order of norm\n   * @param {number} [dim=null] Specifies which dimension of the tensor to calculate the norm across.\n   * If dim is None, the norm will be calculated across all dimensions of input.\n   * @param {boolean} [keepdim=false] Whether the output tensors have dim retained or not.\n   * @returns {Tensor} The norm of the tensor.\n   */\n  norm(p: number | string = 'fro', dim: number | null = null, keepdim = false) {\n    if (p === 'fro') {\n      // NOTE: Since we only support integer dims, Frobenius norm produces the same result as p=2.\n      p = 2;\n    } else if (typeof p === 'string') {\n      throw Error(`Unsupported norm: ${p}`);\n    }\n\n    const this_data = this.data;\n    const fn = (a: number, b: number) => a + (b ** p);\n\n    if (dim === null) {\n      // @ts-ignore\n      const val = this_data.reduce(fn, 0) ** (1 / p);\n      return new Tensor(this.type, [val], []);\n    }\n\n    const [type, result, resultDims] = reduce_helper(fn, this, dim, keepdim);\n\n\n    if (p !== 1) {\n      for (let i = 0; i < result.length; ++i) {\n        result[i] = result[i] ** (1 / p);\n      }\n    }\n\n    return new Tensor(type, result, resultDims);\n\n  }\n\n  /**\n   * Performs `L_p` normalization of inputs over specified dimension. Operates in place.\n   * @param {number} [p=2] The exponent value in the norm formulation\n   * @param {number} [dim=1] The dimension to reduce\n   * @returns {Tensor} `this` for operation chaining.\n   */\n  normalize_(p = 2.0, dim = 1) {\n    dim = safeIndex(dim, this.dims.length);\n\n    const norm = this.norm(p, dim, true);\n\n    const this_data = this.data;\n    const norm_data = norm.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      // Calculate the index in the resulting array\n      let resultIndex = 0;\n\n      for (let j = this.dims.length - 1, num = i, resultMultiplier = 1; j >= 0; --j) {\n        const size = this.dims[j];\n        if (j !== dim) {\n          const index = num % size;\n          resultIndex += index * resultMultiplier;\n          resultMultiplier *= this.dims[j];\n        }\n        num = Math.floor(num / size);\n      }\n\n      // Divide by normalized value\n      this_data[i] /= norm_data[resultIndex];\n    }\n\n    return this;\n  }\n\n  /**\n   * Performs `L_p` normalization of inputs over specified dimension.\n   * @param {number} [p=2] The exponent value in the norm formulation\n   * @param {number} [dim=1] The dimension to reduce\n   * @returns {Tensor} The normalized tensor.\n   */\n  normalize(p = 2.0, dim = 1) {\n    return this.clone().normalize_(p, dim);\n  }\n\n  /**\n   * Compute and return the stride of this tensor.\n   * Stride is the jump necessary to go from one element to the next one in the specified dimension dim.\n   * @returns {number[]} The stride of this tensor.\n   */\n  stride() {\n    return dimsToStride(this.dims);\n  }\n\n  /**\n   * Returns a tensor with all specified dimensions of input of size 1 removed.\n   *\n   * NOTE: The returned tensor shares the storage with the input tensor, so changing the contents of one will change the contents of the other.\n   * If you would like a copy, use `tensor.clone()` before squeezing.\n   *\n   * @param {number|number[]} [dim=null] If given, the input will be squeezed only in the specified dimensions.\n   * @returns {Tensor} The squeezed tensor\n   */\n  squeeze(dim: number | number[] | null = null) {\n    return new Tensor(this.type, this.data, calc_squeeze_dims(this.dims, dim));\n  }\n\n  /**\n   * In-place version of @see {@link Tensor.squeeze}\n   */\n  squeeze_(dim: number | null = null) {\n    this.dims = calc_squeeze_dims(this.dims, dim);\n    return this;\n  }\n\n  /**\n   * Returns a new tensor with a dimension of size one inserted at the specified position.\n   *\n   * NOTE: The returned tensor shares the same underlying data with this tensor.\n   *\n   * @param {number} dim The index at which to insert the singleton dimension\n   * @returns {Tensor} The unsqueezed tensor\n   */\n  unsqueeze(dim: number) {\n    return new Tensor(this.type, this.data, calc_unsqueeze_dims(this.dims, dim));\n  }\n\n  /**\n   * In-place version of @see {@link Tensor.unsqueeze}\n   */\n  unsqueeze_(dim: number) {\n    this.dims = calc_unsqueeze_dims(this.dims, dim);\n    return this;\n  }\n\n  /**\n   * In-place version of @see {@link Tensor.flatten}\n   */\n  flatten_(start_dim = 0, end_dim = -1) {\n    // TODO validate inputs\n    end_dim = (end_dim + this.dims.length) % this.dims.length;\n\n    let dimsToKeepBefore = this.dims.slice(0, start_dim);\n    let dimsToFlatten = this.dims.slice(start_dim, end_dim + 1);\n    let dimsToKeepAfter = this.dims.slice(end_dim + 1);\n\n    this.dims = [...dimsToKeepBefore, dimsToFlatten.reduce((a: number, b: number) => a * b, 1), ...dimsToKeepAfter];\n    return this;\n  }\n\n  /**\n   * Flattens input by reshaping it into a one-dimensional tensor.\n   * If `start_dim` or `end_dim` are passed, only dimensions starting with `start_dim`\n   * and ending with `end_dim` are flattened. The order of elements in input is unchanged.\n   * @param {number} start_dim the first dim to flatten\n   * @param {number} end_dim the last dim to flatten\n   * @returns {Tensor} The flattened tensor.\n   */\n  flatten(start_dim = 0, end_dim = -1) {\n    return this.clone().flatten_(start_dim, end_dim);\n  }\n\n  /**\n   * Returns a new tensor with the same data as the `self` tensor but of a different `shape`.\n   * @param  {...number} dims the desired size\n   * @returns {Tensor} The tensor with the same data but different shape\n   */\n  view(...dims: number[]) {\n    // TODO: validate dims\n    let inferredIndex = -1;\n    for (let i = 0; i < dims.length; ++i) {\n      if (dims[i] === -1) {\n        if (inferredIndex !== -1) {\n          throw new Error('Only one dimension can be inferred');\n        }\n        inferredIndex = i;\n      }\n    }\n\n    const this_data = this.data;\n    if (inferredIndex !== -1) {\n      // Some dimension must be inferred\n      const productOther = dims.reduce((product, curr, index) => {\n        return index !== inferredIndex ? product * curr : product;\n      }, 1);\n\n      dims[inferredIndex] = this_data.length / productOther;\n    }\n    return new Tensor(this.type, this_data, dims); // NOTE: uses same underlying storage\n  }\n\n  neg_() {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] = -this_data[i];\n    }\n    return this;\n  }\n  neg() {\n    return this.clone().neg_();\n  }\n\n  /**\n  * Computes input > val element-wise.\n  * @param {number} val The value to compare with.\n  * @returns {Tensor} A boolean tensor that is `true` where input is greater than other and `false` elsewhere.\n  */\n  gt(val: number) {\n    const mask = new Uint8Array(this.data.length);\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      mask[i] = this_data[i] > val ? 1 : 0;\n    }\n    return new Tensor('bool', mask, this.dims);\n  }\n\n  /**\n   * Computes input < val element-wise.\n   * @param {number} val The value to compare with.\n   * @returns {Tensor} A boolean tensor that is `true` where input is less than other and `false` elsewhere.\n   */\n  lt(val: number) {\n    const mask = new Uint8Array(this.data.length);\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      mask[i] = this_data[i] < val ? 1 : 0;\n    }\n    return new Tensor('bool', mask, this.dims);\n  }\n\n  /**\n   * In-place version of @see {@link Tensor.clamp}\n   */\n  clamp_(min: number, max: number) {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] = Math.min(Math.max(this_data[i], min), max);\n    }\n    return this;\n  }\n\n  /**\n   * Clamps all elements in input into the range [ min, max ]\n   * @param {number} min lower-bound of the range to be clamped to\n   * @param {number} max upper-bound of the range to be clamped to\n   * @returns {Tensor} the output tensor.\n   */\n  clamp(min: number, max: number) {\n    return this.clone().clamp_(min, max);\n  }\n\n  /**\n   * In-place version of @see {@link Tensor.round}\n   */\n  round_() {\n    const this_data = this.data;\n    for (let i = 0; i < this_data.length; ++i) {\n      this_data[i] = Math.round(this_data[i]);\n    }\n    return this;\n  }\n\n  /**\n   * Rounds elements of input to the nearest integer.\n   * @returns {Tensor} the output tensor.\n   */\n  round() {\n    return this.clone().round_();\n  }\n\n  mean(dim = null, keepdim = false) {\n    return mean(this, dim, keepdim);\n  }\n\n  min(dim = null, keepdim = false) {\n    if (dim !== null) {\n      const val = min(this.data as any)[0];\n      return new Tensor(this.type, [val], [/* scalar */]);\n    }\n    const [type, result, resultDims] = reduce_helper((a: any, b: any) => Math.min(a, b), this, dim, keepdim, Infinity);\n    return new Tensor(type, result, resultDims);\n  }\n  max(dim = null, keepdim = false) {\n    if (dim === null) {\n      // None to reduce over all dimensions.\n      const val = max(this.data as any)[0];\n      return new Tensor(this.type, [val], [/* scalar */]);\n    }\n    const [type, result, resultDims] = reduce_helper((a: any, b: any) => Math.max(a, b), this, dim, keepdim, -Infinity);\n    return new Tensor(type, result, resultDims);\n  }\n\n  argmin(dim = null, keepdim = false) {\n    if (dim !== null) {\n      throw new Error('`dim !== null` not yet implemented.');\n    }\n    const index = min(this.data as any)[1];\n    return new Tensor('int64', [BigInt(index)], []);\n  }\n  argmax(dim = null, keepdim = false) {\n    if (dim !== null) {\n      throw new Error('`dim !== null` not yet implemented.');\n    }\n    const index = max(this.data as any)[1];\n    return new Tensor('int64', [BigInt(index)], []);\n  }\n\n  /**\n   * Performs Tensor dtype conversion.\n   * @param {DataType} type The desired data type.\n   * @returns {Tensor} The converted tensor.\n   */\n  to(type: DataType) {\n    // If the self Tensor already has the correct dtype, then self is returned.\n    if (this.type === type) return this;\n\n    // Otherwise, the returned tensor is a copy of self with the desired dtype.\n    if (!DataTypeMap.hasOwnProperty(type)) {\n      throw new Error(`Unsupported type: ${type}`);\n    }\n\n    // Handle special cases where a mapping function is needed (e.g., where one type is a bigint and the other is a number)\n    let map_fn;\n    const is_source_bigint = ['int64', 'uint64'].includes(this.type);\n    const is_dest_bigint = ['int64', 'uint64'].includes(type);\n    if (is_source_bigint && !is_dest_bigint) {\n      // TypeError: Cannot convert a BigInt value to a number\n      map_fn = Number;\n    } else if (!is_source_bigint && is_dest_bigint) {\n      // TypeError: Cannot convert [x] to a BigInt\n      map_fn = BigInt;\n    }\n\n    // @ts-ignore\n    return new Tensor(type, DataTypeMap[type].from(this.data, map_fn), this.dims);\n  }\n}\n\n/**\n * This creates a nested array of a given type and depth (see examples).\n *\n * @example\n *   NestArray<string, 1>; // string[]\n * @example\n *   NestArray<number, 2>; // number[][]\n * @example\n *   NestArray<string, 3>; // string[][][] etc.\n * @template T\n * @template {number} Depth\n * @template {never[]} [Acc=[]]\n * @typedef {Acc['length'] extends Depth ? T : NestArray<T[], Depth, [...Acc, never]>} NestArray\n */\n\n/**\n * Reshapes a 1-dimensional array into an n-dimensional array, according to the provided dimensions.\n *\n * @example\n *   reshape([10                    ], [1      ]); // Type: number[]      Value: [10]\n *   reshape([1, 2, 3, 4            ], [2, 2   ]); // Type: number[][]    Value: [[1, 2], [3, 4]]\n *   reshape([1, 2, 3, 4, 5, 6, 7, 8], [2, 2, 2]); // Type: number[][][]  Value: [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]\n *   reshape([1, 2, 3, 4, 5, 6, 7, 8], [4, 2   ]); // Type: number[][]    Value: [[1, 2], [3, 4], [5, 6], [7, 8]]\n * @param {T[]|DataArray} data The input array to reshape.\n * @param {DIM} dimensions The target shape/dimensions.\n * @template T\n * @template {[number]|number[]} DIM\n * @returns {NestArray<T, DIM[\"length\"]>} The reshaped array.\n */\nfunction reshape(data: DataArray, dimensions: number[]) {\n  const totalElements = data.length;\n  const dimensionSize = dimensions.reduce((a, b) => a * b);\n\n  if (totalElements !== dimensionSize) {\n    throw Error(`cannot reshape array of size ${totalElements} into shape (${dimensions})`);\n  }\n\n  /** @type {any} */\n  let reshapedArray = data;\n\n  for (let i = dimensions.length - 1; i >= 0; i--) {\n    reshapedArray = (reshapedArray as any[]).reduce(\n      (acc: any[], val: any) => {\n        let lastArray = acc[acc.length - 1];\n\n        if (lastArray.length < dimensions[i]) {\n          lastArray.push(val);\n        } else {\n          acc.push([val]);\n        }\n\n        return acc;\n      },\n      [[]],\n    );\n  }\n\n  return reshapedArray[0];\n}\n\n/**\n * Permutes a tensor according to the provided axes.\n * @param {any} tensor The input tensor to permute.\n * @param {Array} axes The axes to permute the tensor along.\n * @returns {Tensor} The permuted tensor.\n */\nexport function permute(tensor: Tensor, axes: number[]) {\n  const [permutedData, shape] = permute_data(tensor.data as any, tensor.dims, axes);\n  return new Tensor(tensor.type, permutedData, shape);\n}\n\n/**\n * Interpolates an Tensor to the given size.\n * @param {Tensor} input The input tensor to interpolate. Data must be channel-first (i.e., [c, h, w])\n * @param {number[]} size The output size of the image\n * @param {string} mode The interpolation mode\n * @param {boolean} align_corners Whether to align corners.\n * @returns {Tensor} The interpolated tensor.\n */\nexport function interpolate(\n  input: Tensor,\n  [out_height, out_width]: number[],\n  mode: string = 'bilinear',\n  align_corners: boolean = false,\n) {\n  // Input image dimensions\n  const in_channels = input.dims.at(-3) ?? 1;\n  const in_height = input.dims.at(-2);\n  const in_width = input.dims.at(-1);\n\n  let output = interpolate_data(\n    /** @type {import('./maths.js').TypedArray}*/ input.data as any,\n    [in_channels, in_height, in_width],\n    [out_height, out_width],\n    mode,\n    align_corners,\n  );\n  return new Tensor(input.type, output, [in_channels, out_height, out_width]);\n}\n\n/**\n * Down/up samples the input.\n * Inspired by https://pytorch.org/docs/stable/generated/torch.nn.functional.interpolate.html.\n * @param {Tensor} input the input tensor\n * @param {Object} options the options for the interpolation\n * @param {[number, number]|[number, number, number]|[number, number, number, number]} [options.size=null] output spatial size.\n * @param {\"nearest\"|\"bilinear\"|\"bicubic\"} [options.mode='bilinear'] algorithm used for upsampling\n * @returns {Promise<Tensor>} The interpolated tensor.\n */\nexport async function interpolate_4d(input: Tensor, { size = null as number[] | null, mode = 'bilinear' } = {}) {\n  // Error checking\n  if (input.dims.length !== 4) {\n    throw new Error('`interpolate_4d` currently only supports 4D input.');\n  }\n  if (!size) {\n    // TODO: support scale_factor\n    throw new Error('`interpolate_4d` requires a `size` argument.');\n  }\n\n  // Fill in missing dimensions\n  let targetDims;\n  if (size.length === 2) {\n    targetDims = [...input.dims.slice(0, 2), ...size];\n  } else if (size.length === 3) {\n    targetDims = [input.dims[0], ...size];\n  } else if (size.length === 4) {\n    targetDims = size;\n  } else {\n    throw new Error('`size` must be of length 2, 3, or 4.');\n  }\n\n  let op;\n  if (mode === 'nearest') {\n    op = await TensorOpRegistry.nearest_interpolate_4d;\n  } else if (mode === 'bilinear') {\n    op = await TensorOpRegistry.bilinear_interpolate_4d;\n  } else if (mode === 'bicubic') {\n    op = await TensorOpRegistry.bicubic_interpolate_4d;\n  } else {\n    throw new Error(`Unsupported mode: ${mode}`);\n  }\n\n  const sizeTensor = new Tensor('int64', new BigInt64Array(targetDims.map(BigInt)), [targetDims.length]);\n  return await op({ x: input, s: sizeTensor });\n}\n\n/**\n * Matrix product of two tensors.\n * Inspired by https://pytorch.org/docs/stable/generated/torch.matmul.html\n * @param {Tensor} a the first tensor to be multiplied\n * @param {Tensor} b the second tensor to be multiplied\n * @returns {Promise<Tensor>} The matrix product of the two tensors.\n */\nexport async function matmul(a: Tensor, b: Tensor) {\n  const op = await TensorOpRegistry.matmul;\n  return await op({ a, b });\n}\n\n/**\n * Computes the one dimensional Fourier transform of real-valued input.\n * Inspired by https://pytorch.org/docs/stable/generated/torch.fft.rfft.html\n * @param {Tensor} x the real input tensor\n * @param {Tensor} a The dimension along which to take the one dimensional real FFT.\n * @returns {Promise<Tensor>} the output tensor.\n */\nexport async function rfft(x: Tensor, a: Tensor) {\n  const op = await TensorOpRegistry.rfft;\n  return await op({ x, a });\n}\n\n/**\n * Returns the k largest elements of the given input tensor.\n * Inspired by https://pytorch.org/docs/stable/generated/torch.topk.html\n * @param {Tensor} x the input tensor\n * @param {number} [k] the k in \"top-k\"\n * @returns {Promise<[Tensor, Tensor]>} the output tuple of (Tensor, LongTensor) of top-k elements and their indices.\n */\nexport async function topk(x: Tensor, k: number) {\n  const op = await TensorOpRegistry.top_k;\n\n  if (k == null) {\n    k = x.dims.at(-1);\n  } else {\n    k = Math.min(k, x.dims.at(-1));\n  }\n  return await op({\n    x,\n    k: new Tensor('int64', [BigInt(k)], [1]),\n  });\n}\n\nconst arrayToIndexTensor = (array: number[]) => new Tensor('int64', array, [array.length]);\n/**\n * Slice a multidimensional float32 tensor.\n * @param {Tensor} data: Tensor of data to extract slices from\n * @param {number[]} starts: 1-D array of starting indices of corresponding axis in axes\n * @param {number[]} ends: 1-D array of ending indices (exclusive) of corresponding axis in axes\n * @param {number[]} axes: 1-D array of axes that starts and ends apply to\n * @param {number[]} [steps]: 1-D array of slice step of corresponding axis in axes.\n * @returns {Promise<Tensor>} Sliced data tensor.\n */\nexport async function slice(\n  data: Tensor,\n  starts: number[],\n  ends: number[],\n  axes: number[],\n  steps: number[] | null = null,\n) {\n  const op = await TensorOpRegistry.slice;\n  return await op({\n    x: data,\n    s: arrayToIndexTensor(starts),\n    e: arrayToIndexTensor(ends),\n    a: arrayToIndexTensor(axes),\n    t: arrayToIndexTensor(steps ?? new Array(axes.length).fill(1)),\n  });\n}\n\n/**\n * Perform mean pooling of the last hidden state followed by a normalization step.\n * @param {Tensor} last_hidden_state Tensor of shape [batchSize, seqLength, embedDim]\n * @param {Tensor} attention_mask Tensor of shape [batchSize, seqLength]\n * @returns {Tensor} Returns a new Tensor of shape [batchSize, embedDim].\n */\nexport function mean_pooling(last_hidden_state: Tensor, attention_mask: Tensor) {\n  // last_hidden_state: [batchSize, seqLength, embedDim]\n  // attention_mask:    [batchSize, seqLength]\n  const lastHiddenStateData = last_hidden_state.data;\n  const attentionMaskData = attention_mask.data;\n\n  const shape = [last_hidden_state.dims[0], last_hidden_state.dims[2]];\n\n  // @ts-ignore\n  const returnedData = new lastHiddenStateData.constructor(shape[0] * shape[1]);\n  const [batchSize, seqLength, embedDim] = last_hidden_state.dims;\n\n  let outIndex = 0;\n  for (let i = 0; i < batchSize; ++i) {\n    const offset = i * embedDim * seqLength;\n\n    for (let k = 0; k < embedDim; ++k) {\n      let sum = 0;\n      let count = 0;\n\n      const attnMaskOffset = i * seqLength;\n      const offset2 = offset + k;\n      // Pool over all words in sequence\n      for (let j = 0; j < seqLength; ++j) {\n        // index into attention mask\n        const attn = Number(attentionMaskData[attnMaskOffset + j]);\n\n        count += attn;\n        sum += lastHiddenStateData[offset2 + j * embedDim] * attn;\n      }\n\n      const avg = sum / count;\n      returnedData[outIndex++] = avg;\n    }\n  }\n\n  return new Tensor(last_hidden_state.type, returnedData, shape);\n}\n\n/**\n * Apply Layer Normalization for last certain number of dimensions.\n * @param {Tensor} input The input tensor\n * @param {number[]} normalized_shape input shape from an expected input of size\n * @param {Object} options The options for the layer normalization\n * @param {number} [options.eps=1e-5] A value added to the denominator for numerical stability.\n * @returns {Tensor} The normalized tensor.\n */\nexport function layer_norm(input: Tensor, normalized_shape: number[], { eps = 1e-5 } = {}) {\n  if (input.dims.length !== 2) {\n    throw new Error('`layer_norm` currently only supports 2D input.');\n  }\n\n  const [batchSize, featureDim] = input.dims;\n\n  if (normalized_shape.length !== 1 && normalized_shape[0] !== featureDim) {\n    throw new Error('`normalized_shape` must be a 1D array with shape `[input.dims[1]]`.');\n  }\n\n  const [std, mean] = std_mean(input, 1, 0, true);\n  const stdData = /** @type {Float32Array} */ std.data;\n  const meanData = /** @type {Float32Array} */ mean.data;\n\n  const inputData = /** @type {Float32Array} */ input.data;\n\n  // @ts-ignore\n  const returnedData = new inputData.constructor(inputData.length);\n\n  for (let i = 0; i < batchSize; ++i) {\n    const offset = i * featureDim;\n    for (let j = 0; j < featureDim; ++j) {\n      const offset2 = offset + j;\n      returnedData[offset2] = (inputData[offset2] - meanData[i]) / (stdData[i] + eps);\n    }\n  }\n  return new Tensor(input.type, returnedData, input.dims);\n}\n\n/**\n * Helper function to calculate new dimensions when performing a squeeze operation.\n * @param {number[]} dims The dimensions of the tensor.\n * @param {number|number[]|null} dim The dimension(s) to squeeze.\n * @returns {number[]} The new dimensions.\n * @private\n */\nfunction calc_squeeze_dims(dims: number[], dim: number | number[] | null) {\n  dims = dims.slice();\n  if (dim === null) {\n    dims = dims.filter((d) => d !== 1);\n  } else if (typeof dim === 'number') {\n    if (dims[dim] === 1) {\n      dims.splice(dim, 1);\n    }\n  } else if (Array.isArray(dim)) {\n    dims = dims.filter((x, i) => {\n      return x !== 1 || !dim.includes(i);\n    });\n  }\n  return dims;\n}\n\n/**\n * Helper function to calculate new dimensions when performing an unsqueeze operation.\n * @param {number[]} dims The dimensions of the tensor.\n * @param {number} dim The dimension to unsqueeze.\n * @returns {number[]} The new dimensions.\n * @private\n */\nfunction calc_unsqueeze_dims(dims: number[], dim: number) {\n  // Dimension out of range (e.g., \"expected to be in range of [-4, 3], but got 4\")\n  // + 1 since we allow inserting at the end (i.e. dim = -1)\n  dim = safeIndex(dim, dims.length + 1);\n  dims = dims.slice();\n  // Insert 1 into specified dimension\n  dims.splice(dim, 0, 1);\n  return dims;\n}\n\n/**\n * Safely calculate the index for an array of a given size, allowing negative indexing.\n * @param {number} index The index that will be used.\n * @param {number} size The size of the array.\n * @param {number} [dimension=null] The dimension that the index is for (optional).\n * @returns {number} The index, guaranteed to be non-negative and less than `arrayLength`.\n *\n * @throws {Error} If the index is out of range.\n * @private\n */\nfunction safeIndex(index: number, size: number, dimension: number | null = null, boundsCheck: boolean = true) {\n  if (boundsCheck && (index < -size || index >= size)) {\n    throw new Error(\n      `IndexError: index ${index} is out of bounds for dimension${dimension === null ? '' : ' ' + dimension} with size ${size}`,\n    );\n  }\n\n  if (index < 0) {\n    // Negative indexing, ensuring positive index\n    index = ((index % size) + size) % size;\n  }\n  return index;\n}\n\n/**\n * Concatenates an array of tensors along a specified dimension.\n * @param {Tensor[]} tensors The array of tensors to concatenate.\n * @param {number} dim The dimension to concatenate along.\n * @returns {Tensor} The concatenated tensor.\n */\nexport function cat(tensors: Tensor[], dim: number = 0) {\n  dim = safeIndex(dim, tensors[0].dims.length);\n\n  // TODO do validation of shapes\n\n  const resultDims = tensors[0].dims.slice();\n  resultDims[dim] = tensors.reduce((a, b) => a + b.dims[dim], 0);\n\n  // Create a new array to store the accumulated values\n  const resultSize = resultDims.reduce((a: number, b: number) => a * b, 1);\n  // @ts-ignore\n  const result = new tensors[0].data.constructor(resultSize);\n\n  // Create output tensor of same type as first\n  const resultType = tensors[0].type;\n\n  if (dim === 0) {\n    // Handle special case for performance reasons\n\n    let offset = 0;\n    for (const tensor of tensors) {\n      const tensorData = tensor.data;\n      result.set(tensorData, offset);\n      offset += tensorData.length;\n    }\n  } else {\n    let currentDim = 0;\n\n    for (let t = 0; t < tensors.length; ++t) {\n      const { data, dims } = tensors[t];\n\n      // Iterate over the data array\n      for (let i = 0; i < data.length; ++i) {\n        // Calculate the index in the resulting array\n        let resultIndex = 0;\n\n        for (let j = dims.length - 1, num = i, resultMultiplier = 1; j >= 0; --j) {\n          const size = dims[j];\n          let index = num % size;\n          if (j === dim) {\n            index += currentDim;\n          }\n          resultIndex += index * resultMultiplier;\n          resultMultiplier *= resultDims[j];\n          num = Math.floor(num / size);\n        }\n        // Accumulate the value at the current index\n        result[resultIndex] = data[i];\n      }\n\n      currentDim += dims[dim];\n    }\n  }\n  return new Tensor(resultType, result, resultDims);\n}\n\n/**\n * Stack an array of tensors along a specified dimension.\n * @param {Tensor[]} tensors The array of tensors to stack.\n * @param {number} dim The dimension to stack along.\n * @returns {Tensor} The stacked tensor.\n */\nexport function stack(tensors: Tensor[], dim: number = 0) {\n  // TODO do validation of shapes\n  // NOTE: stack expects each tensor to be equal size\n  return cat(\n    tensors.map((t) => t.unsqueeze(dim)),\n    dim,\n  );\n}\n\n/**\n * @param {(previousValue: any, currentValue: any, currentIndex?: number, resultIndex?: number) => any} callbackfn\n * @param {Tensor} input the input tensor.\n * @param {number|null} dim the dimension to reduce.\n * @param {boolean} keepdim whether the output tensor has dim retained or not.\n * @returns {[DataType, any, number[]]} The reduced tensor data.\n */\nfunction reduce_helper(callbackfn: any, input: Tensor, dim: number | number[] | null = null, keepdim = false, initialValue: number | null = null) {\n  const inputData = input.data;\n  const inputDims = input.dims;\n\n  // Negative indexing\n  dim = safeIndex(dim as number, inputDims.length);\n\n  // Calculate the shape of the resulting array after summation\n  const resultDims = inputDims.slice(); // Copy the original dimensions\n  resultDims[dim] = 1; // Remove the specified axis\n\n  // Create a new array to store the accumulated values\n  // @ts-ignore\n  const result = new inputData.constructor(inputData.length / inputDims[dim]);\n  if (initialValue !== null) {\n    result.fill(initialValue);\n  }\n\n  // Iterate over the data array\n  for (let i = 0; i < inputData.length; ++i) {\n\n    // Calculate the index in the resulting array\n    let resultIndex = 0;\n\n    for (let j = inputDims.length - 1, num = i, resultMultiplier = 1; j >= 0; --j) {\n      const size = inputDims[j];\n      if (j !== dim) {\n        const index = num % size;\n        resultIndex += index * resultMultiplier;\n        resultMultiplier *= resultDims[j];\n      }\n      num = Math.floor(num / size);\n    }\n\n    // Accumulate the value at the current index\n    result[resultIndex] = callbackfn(result[resultIndex], inputData[i], i, resultIndex);\n  }\n\n  if (!keepdim) resultDims.splice(dim, 1);\n\n  return [input.type, result, resultDims];\n}\n\n/**\n * Calculates the standard deviation and mean over the dimensions specified by dim. dim can be a single dimension or `null` to reduce over all dimensions.\n * @param {Tensor} input the input tenso\n * @param {number|null} dim the dimension to reduce. If None, all dimensions are reduced.\n * @param {number} correction difference between the sample size and sample degrees of freedom. Defaults to Bessel's correction, correction=1.\n * @param {boolean} keepdim whether the output tensor has dim retained or not.\n * @returns {Tensor[]} A tuple of (std, mean) tensors.\n */\nexport function std_mean(input: Tensor, dim: number | null = null, correction = 1, keepdim = false) {\n  const inputData: any = /** @type {Float32Array} */(input.data);\n  const inputDims = input.dims;\n\n  if (dim === null) {\n      // None to reduce over all dimensions.\n      const sum = inputData.reduce((a: number, b: number) => a + b, 0);\n      const mean = sum / inputData.length;\n      const std = Math.sqrt(inputData.reduce((a: number, b: number) => a + (b - mean) ** 2, 0) / (inputData.length - correction));\n\n      const meanTensor = new Tensor(input.type, [mean], [/* scalar */]);\n      const stdTensor = new Tensor(input.type, [std], [/* scalar */]);\n\n      return [stdTensor, meanTensor];\n  }\n  dim = safeIndex(dim, inputDims.length);\n  const meanTensor = mean(input, dim, keepdim);\n  const meanTensorData = meanTensor.data;\n\n  // Compute squared sum\n  const [type, result, resultDims] = reduce_helper((a: any, b: any, i: any, j: any) => a + (b - meanTensorData[j]) ** 2, input, dim, keepdim);\n\n  // Square root of the squared sum\n  for (let i = 0; i < result.length; ++i) {\n      result[i] = Math.sqrt(result[i] / (inputDims[dim] - correction));\n  }\n\n  const stdTensor = new Tensor(type, result, resultDims);\n\n  return [stdTensor, meanTensor];\n}\n\n\n/**\n * Returns the mean value of each row of the input tensor in the given dimension dim.\n * @param {Tensor} input the input tensor.\n * @param {number|null} dim the dimension to reduce.\n * @param {boolean} keepdim whether the output tensor has dim retained or not.\n * @returns {Tensor} A new tensor with means taken along the specified dimension.\n */\nexport function mean(input: Tensor, dim: number | null = null, keepdim: boolean = false) {\n  const inputData = /** @type {Float32Array} */ input.data;\n  const inputDims = input.dims;\n\n  if (dim === null) {\n    // None to reduce over all dimensions.\n    // @ts-ignore\n    const val = inputData.reduce((a: number, b: number) => a + b, 0);\n    return new Tensor(\n      input.type,\n      [val / inputData.length],\n      [\n        /* scalar */\n      ],\n    );\n  }\n\n  // Negative indexing\n  dim = safeIndex(dim, inputDims.length);\n\n  const [type, result, resultDims] = reduce_helper((a: any, b: any) => a + b, input, dim, keepdim);\n\n  return new Tensor(type, result, resultDims);\n}\n\nfunction dimsToStride(dims: number[]) {\n  const stride = new Array(dims.length);\n  for (let i = dims.length - 1, s2 = 1; i >= 0; --i) {\n    stride[i] = s2;\n    s2 *= dims[i];\n  }\n  return stride;\n}\n\nfunction fullHelper(\n  size: number[],\n  fill_value: number | bigint | boolean,\n  dtype: string,\n  cls: new (length: number) => TypedArray,\n) {\n  const numElements = size.reduce((a, b) => a * b, 1);\n  return new Tensor(\n    dtype as keyof typeof DataTypeMap,\n    new cls(numElements).fill(fill_value as number & bigint & boolean) as TypedArray,\n    size,\n  );\n}\n\n/**\n * Creates a tensor of size size filled with fill_value. The tensor's dtype is inferred from fill_value.\n * @param {number[]} size A sequence of integers defining the shape of the output tensor.\n * @param {number|bigint|boolean} fill_value The value to fill the output tensor with.\n * @returns {Tensor} The filled tensor.\n */\nexport function full(size: number[], fill_value: number | bigint | boolean) {\n  let dtype;\n  let typedArrayCls;\n  if (typeof fill_value === 'number') {\n    dtype = 'float32';\n    typedArrayCls = Float32Array;\n  } else if (typeof fill_value === 'bigint') {\n    dtype = 'int64';\n    typedArrayCls = BigInt64Array;\n  } else if (typeof fill_value === 'boolean') {\n    dtype = 'bool';\n    typedArrayCls = Uint8Array;\n  } else {\n    // TODO: support other dtypes\n    throw new Error(`Unsupported data type: ${typeof fill_value}`);\n  }\n  return fullHelper(size, fill_value, dtype, typedArrayCls);\n}\n\nexport function full_like(tensor: Tensor, fill_value: number | bigint | boolean) {\n  return full(tensor.dims, fill_value);\n}\n\n/**\n * Returns a tensor filled with the scalar value 1, with the shape defined by the variable argument size.\n * @param {number[]} size A sequence of integers defining the shape of the output tensor.\n * @returns {Tensor} The ones tensor.\n */\nexport function ones(size: number[]) {\n  return fullHelper(size, 1n, 'int64', BigInt64Array);\n}\n\n/**\n * Returns a tensor filled with the scalar value 1, with the same size as input.\n * @param {Tensor} tensor The size of input will determine size of the output tensor.\n * @returns {Tensor} The ones tensor.\n */\nexport function ones_like(tensor: Tensor) {\n  return ones(tensor.dims);\n}\n\n/**\n * Returns a tensor filled with the scalar value 0, with the shape defined by the variable argument size.\n * @param {number[]} size A sequence of integers defining the shape of the output tensor.\n * @returns {Tensor} The zeros tensor.\n */\nexport function zeros(size: number[]) {\n  return fullHelper(size, 0n, 'int64', BigInt64Array);\n}\n\n/**\n * Returns a tensor filled with the scalar value 0, with the same size as input.\n * @param {Tensor} tensor The size of input will determine size of the output tensor.\n * @returns {Tensor} The zeros tensor.\n */\nexport function zeros_like(tensor: Tensor) {\n  return zeros(tensor.dims);\n}\n\n/**\n * Returns a tensor filled with random numbers from a uniform distribution on the interval [0, 1)\n * @param {number[]} size A sequence of integers defining the shape of the output tensor.\n * @returns {Tensor} The random tensor.\n */\nexport function rand(size: number[]) {\n  const length = size.reduce((a, b) => a * b, 1);\n  return new Tensor(\n    'float32',\n    Float32Array.from({ length }, () => Math.random()),\n    size,\n  );\n}\n\n/**\n * Quantizes the embeddings tensor to binary or unsigned binary precision.\n * @param {Tensor} tensor The tensor to quantize.\n * @param {'binary'|'ubinary'} precision The precision to use for quantization.\n * @returns {Tensor} The quantized tensor.\n */\nexport function quantize_embeddings(tensor: Tensor, precision: 'binary' | 'ubinary') {\n  if (tensor.dims.length !== 2) {\n    throw new Error('The tensor must have 2 dimensions');\n  }\n  if (tensor.dims.at(-1) % 8 !== 0) {\n    throw new Error('The last dimension of the tensor must be a multiple of 8');\n  }\n  if (!['binary', 'ubinary'].includes(precision)) {\n    throw new Error(\"The precision must be either 'binary' or 'ubinary'\");\n  }\n\n  const signed = precision === 'binary';\n  const dtype = signed ? 'int8' : 'uint8';\n\n  // Create a typed array to store the packed bits\n  const cls = signed ? Int8Array : Uint8Array;\n  const inputData = tensor.data;\n  const outputData = new cls(inputData.length / 8);\n\n  // Iterate over each number in the array\n  for (let i = 0; i < inputData.length; ++i) {\n    // Determine if the number is greater than 0\n    const bit = inputData[i] > 0 ? 1 : 0;\n\n    // Calculate the index in the typed array and the position within the byte\n    const arrayIndex = Math.floor(i / 8);\n    const bitPosition = i % 8;\n\n    // Pack the bit into the typed array\n    outputData[arrayIndex] |= bit << (7 - bitPosition);\n    if (signed && bitPosition === 0) {\n      outputData[arrayIndex] -= 128;\n    }\n  }\n\n  return new Tensor(dtype, outputData, [tensor.dims[0], tensor.dims[1] / 8]);\n}\n","/**\n * @file Custom data structures.\n *\n * These are only used internally, meaning an end-user shouldn't\n * need to access anything here.\n *\n * @module utils/data-structures\n */\n\n/**\n * Efficient Heap-based Implementation of a Priority Queue.\n * It uses an array-based binary heap, where the root is at index `0`, and the\n * children of node `i` are located at indices `2i + 1` and `2i + 2`, respectively.\n *\n * Adapted from the following sources:\n * - https://stackoverflow.com/a/42919752/13989043 (original)\n * - https://github.com/belladoreai/llama-tokenizer-js (minor improvements)\n */\nexport class PriorityQueue {\n  /**\n   * Create a new PriorityQueue.\n   * @param {function(any, any): boolean} comparator Comparator function to determine priority. Defaults to a MaxHeap.\n   */\n  _comparator: (a: any, b: any) => boolean;\n  _maxSize: number;\n  _heap: any[];\n\n  constructor(comparator = (a: any, b: any) => a > b, maxSize = Infinity) {\n    this._heap = [];\n    this._comparator = comparator;\n    this._maxSize = maxSize;\n  }\n\n  /**\n   * The size of the queue\n   */\n  get size() {\n    return this._heap.length;\n  }\n\n  /**\n   * Check if the queue is empty.\n   * @returns {boolean} `true` if the queue is empty, `false` otherwise.\n   */\n  isEmpty() {\n    return this.size === 0;\n  }\n\n  /**\n   * Return the element with the highest priority in the queue.\n   * @returns {any} The highest priority element in the queue.\n   */\n  peek() {\n    return this._heap[0];\n  }\n\n  /**\n   * Add one or more elements to the queue.\n   * @param  {...any} values The values to push into the queue.\n   * @returns {number} The new size of the queue.\n   */\n  push(...values: any[]) {\n    return this.extend(values);\n  }\n\n  /**\n   * Add multiple elements to the queue.\n   * @param {any[]} values The values to push into the queue.\n   * @returns {number} The new size of the queue.\n   */\n  extend(values: any[]) {\n    for (const value of values) {\n      if (this.size < this._maxSize) {\n        this._heap.push(value);\n        this._siftUp();\n      } else {\n        // Get index of value with the lowest priority\n        const smallest = this._smallest();\n\n        // If the new value has higher priority than the smallest value in the heap\n        // then replace the smallest value with the new value and update the heap\n        if (this._comparator(value, this._heap[smallest])) {\n          this._heap[smallest] = value;\n          this._siftUpFrom(smallest);\n        }\n      }\n    }\n    return this.size;\n  }\n\n  /**\n   * Remove and return the element with the highest priority in the queue.\n   * @returns {any} The element with the highest priority in the queue.\n   */\n  pop() {\n    const poppedValue = this.peek();\n    const bottom = this.size - 1;\n    if (bottom > 0) {\n      this._swap(0, bottom);\n    }\n    this._heap.pop();\n    this._siftDown();\n    return poppedValue;\n  }\n\n  /**\n   * Replace the element with the highest priority in the queue with a new value.\n   * @param {*} value The new value.\n   * @returns {*} The replaced value.\n   */\n  replace(value: any) {\n    const replacedValue = this.peek();\n    this._heap[0] = value;\n    this._siftDown();\n    return replacedValue;\n  }\n\n  /**\n   * Compute the index for the parent of the node at index `i`.\n   * @param {number} i The index of the node to get the parent of.\n   * @returns {number} The index of the parent node.\n   * @private\n   */\n  _parent(i: number) {\n    return ((i + 1) >>> 1) - 1;\n  }\n\n  /**\n   * Compute the index for the left child of the node at index `i`.\n   * @param {number} i The index of the node to get the left child of.\n   * @returns {number} The index of the left child.\n   * @private\n   */\n  _left(i: number) {\n    return (i << 1) + 1;\n  }\n\n  /**\n   * Compute the index for the right child of the node at index `i`.\n   * @param {number} i The index of the node to get the right child of.\n   * @returns {number} The index of the right child.\n   * @private\n   */\n  _right(i: number) {\n    return (i + 1) << 1;\n  }\n\n  /**\n   * Check if the element at index `i` is greater than the element at index `j`.\n   * @param {number} i The index of the first element to compare.\n   * @param {number} j The index of the second element to compare.\n   * @returns {boolean} `true` if the element at index `i` is greater than the element at index `j`, `false` otherwise.\n   * @private\n   */\n  _greater(i: number, j: number) {\n    return this._comparator(this._heap[i], this._heap[j]);\n  }\n\n  /**\n   * Swap the elements at indices `i` and `j`.\n   * @param {number} i The index of the first element to swap.\n   * @param {number} j The index of the second element to swap.\n   * @private\n   */\n  _swap(i: number, j: number) {\n    const temp = this._heap[i];\n    this._heap[i] = this._heap[j];\n    this._heap[j] = temp;\n  }\n\n  /**\n   * Maintain the heap property by updating positions in the heap,\n   * starting at the last element and moving up the heap.\n   * @private\n   */\n  _siftUp() {\n    this._siftUpFrom(this.size - 1);\n  }\n\n  /**\n   * Helper function to sift up from a given node.\n   * @param {number} node The index of the node to start sifting up from.\n   */\n  _siftUpFrom(node: number) {\n    while (node > 0 && this._greater(node, this._parent(node))) {\n      this._swap(node, this._parent(node));\n      node = this._parent(node);\n    }\n  }\n\n  /**\n   * Maintain the heap property by updating positions in the heap,\n   * starting at the first element and moving down the heap.\n   * @private\n   */\n  _siftDown() {\n    let node = 0;\n    while (\n      (this._left(node) < this.size && this._greater(this._left(node), node)) ||\n      (this._right(node) < this.size && this._greater(this._right(node), node))\n    ) {\n      const maxChild =\n        this._right(node) < this.size && this._greater(this._right(node), this._left(node))\n          ? this._right(node)\n          : this._left(node);\n      this._swap(node, maxChild);\n      node = maxChild;\n    }\n  }\n\n  /**\n   * Get the index of the smallest element in the heap. Since we use an array-based heap,\n   * the index can be computed without needing to traverse the heap.\n   * @private\n   */\n  _smallest() {\n    return 2 ** Math.floor(Math.log2(this.size)) - 1;\n  }\n}\n\n/**\n * A trie structure to efficiently store and search for strings.\n */\nexport class CharTrie {\n  _root: CharTrieNode;\n\n  constructor() {\n    this._root = CharTrieNode.default();\n  }\n\n  /**\n   * Adds one or more `texts` to the trie.\n   * @param {string[]} texts The strings to add to the trie.\n   */\n  extend(texts: string[]) {\n    for (const text of texts) {\n      this.push(text);\n    }\n  }\n\n  /**\n   * Adds text to the trie.\n   * @param {string} text The string to add to the trie.\n   */\n  push(text: string) {\n    let node = this._root;\n    for (const ch of text) {\n      let child = node.children.get(ch);\n      if (child === undefined) {\n        child = CharTrieNode.default();\n        node.children.set(ch, child);\n      }\n      node = child;\n    }\n    node.isLeaf = true;\n  }\n\n  /**\n   * Searches the trie for all strings with a common prefix of `text`.\n   * @param {string} text The common prefix to search for.\n   * @yields {string} Each string in the trie that has `text` as a prefix.\n   */\n  *commonPrefixSearch(text: string) {\n    let node = this._root;\n    if (node === undefined) return;\n\n    let prefix = '';\n    for (const ch of text) {\n      prefix += ch;\n      const nextNode = node.children.get(ch);\n      if (nextNode === undefined) return;\n      node = nextNode;\n      if (node.isLeaf) {\n        yield prefix;\n      }\n    }\n  }\n}\n\n/**\n * Represents a node in a character trie.\n */\nclass CharTrieNode {\n  /**\n   * Create a new CharTrieNode.\n   * @param {boolean} isLeaf Whether the node is a leaf node or not.\n   * @param {Map<string, CharTrieNode>} children A map containing the node's children, where the key is a character and the value is a `CharTrieNode`.\n   */\n  isLeaf: boolean;\n  children: Map<string, CharTrieNode>;\n\n  constructor(isLeaf: boolean, children: Map<string, CharTrieNode>) {\n    this.isLeaf = isLeaf;\n    this.children = children;\n  }\n\n  /**\n   * Returns a new `CharTrieNode` instance with default values.\n   * @returns {CharTrieNode} A new `CharTrieNode` instance with `isLeaf` set to `false` and an empty `children` map.\n   */\n  static default() {\n    return new CharTrieNode(false, new Map());\n  }\n}\n\n/**\n * A lattice data structure to be used for tokenization.\n */\nexport class TokenLattice {\n  /**\n   * Creates a new TokenLattice instance.\n   *\n   * @param {string} sentence The input sentence to be tokenized.\n   * @param {number} bosTokenId The beginning-of-sequence token ID.\n   * @param {number} eosTokenId The end-of-sequence token ID.\n   */\n  _sentence: string;\n  _bosTokenId: number;\n  _eosTokenId: number;\n  _chars: string[];\n  _len: number;\n  _nodes: TokenLatticeNode[];\n  beginNodes: TokenLatticeNode[][];\n  endNodes: TokenLatticeNode[][];\n\n  constructor(sentence: string, bosTokenId: number, eosTokenId: number) {\n    this._sentence = sentence;\n    this._chars = Array.from(sentence);\n    this._len = this._chars.length;\n    this._bosTokenId = bosTokenId;\n    this._eosTokenId = eosTokenId;\n    this._nodes = [];\n    this.beginNodes = Array.from({ length: this._len + 1 }, () => []);\n    this.endNodes = Array.from({ length: this._len + 1 }, () => []);\n\n    const bos = new TokenLatticeNode(this._bosTokenId, 0, 0, 0, 0.0);\n    const eos = new TokenLatticeNode(this._eosTokenId, 1, this._len, 0, 0.0);\n    this._nodes.push(bos.clone());\n    this._nodes.push(eos.clone());\n    this.beginNodes[this._len].push(eos);\n    this.endNodes[0].push(bos);\n  }\n\n  /**\n   * Inserts a new token node into the token lattice.\n   *\n   * @param {number} pos The starting position of the token.\n   * @param {number} length The length of the token.\n   * @param {number} score The score of the token.\n   * @param {number} tokenId The token ID of the token.\n   */\n  insert(pos: number, length: number, score: number, tokenId: number) {\n    const nodeId = this._nodes.length;\n    const node = new TokenLatticeNode(tokenId, nodeId, pos, length, score);\n    this.beginNodes[pos].push(node);\n    this.endNodes[pos + length].push(node);\n    this._nodes.push(node);\n  }\n\n  /**\n   * Implements the Viterbi algorithm to compute the most likely sequence of tokens.\n   *\n   * @returns {TokenLatticeNode[]} The most likely sequence of tokens.\n   */\n  viterbi() {\n    const len = this._len;\n    let pos = 0;\n    while (pos <= len) {\n      if (this.beginNodes[pos].length == 0) {\n        return [];\n      }\n      for (let rnode of this.beginNodes[pos]) {\n        rnode.prev = null;\n        let bestScore = 0.0;\n        let bestNode = null;\n        for (let lnode of this.endNodes[pos]) {\n          const score = lnode.backtraceScore + rnode.score;\n          if (bestNode === null || score > bestScore) {\n            bestNode = lnode.clone();\n            bestScore = score;\n          }\n        }\n\n        if (bestNode !== null) {\n          rnode.prev = bestNode;\n          rnode.backtraceScore = bestScore;\n        } else {\n          return [];\n        }\n      }\n      ++pos;\n    }\n\n    const results = [];\n    const root = this.beginNodes[len][0];\n    const prev = root.prev;\n    if (prev === null) {\n      return [];\n    }\n\n    let node = prev.clone();\n    while (node.prev !== null) {\n      results.push(node.clone());\n      const n = node.clone();\n      if (!n.prev) break;\n      node = n.prev.clone();\n    }\n\n    results.reverse();\n    return results;\n  }\n\n  /**\n   * @param {TokenLatticeNode} node\n   * @returns {string} The array of nodes representing the most likely sequence of tokens.\n   */\n  piece(node: TokenLatticeNode) {\n    return this._chars.slice(node.pos, node.pos + node.length).join('');\n  }\n\n  /**\n   * @returns {string[]} The most likely sequence of tokens.\n   */\n  tokens() {\n    const nodes = this.viterbi();\n    return nodes.map((x) => this.piece(x));\n  }\n\n  /**\n   * @returns {number[]} The most likely sequence of token ids.\n   */\n  tokenIds() {\n    const nodes = this.viterbi();\n    return nodes.map((x) => x.tokenId);\n  }\n}\nclass TokenLatticeNode {\n  /**\n   * Represents a node in a token lattice for a given sentence.\n   * @param {number} tokenId The ID of the token associated with this node.\n   * @param {number} nodeId The ID of this node.\n   * @param {number} pos The starting position of the token in the sentence.\n   * @param {number} length The length of the token.\n   * @param {number} score The score associated with the token.\n   */\n  tokenId: number;\n  nodeId: number;\n  pos: number;\n  length: number;\n  score: number;\n  prev: TokenLatticeNode | null;\n  backtraceScore: number;\n\n  constructor(tokenId: number, nodeId: number, pos: number, length: number, score: number) {\n    this.tokenId = tokenId;\n    this.nodeId = nodeId;\n    this.pos = pos;\n    this.length = length;\n    this.score = score;\n    this.prev = null;\n    this.backtraceScore = 0.0;\n  }\n\n  /**\n   * Returns a clone of this node.\n   * @returns {TokenLatticeNode} A clone of this node.\n   */\n  clone() {\n    const n = new TokenLatticeNode(this.tokenId, this.nodeId, this.pos, this.length, this.score);\n    n.prev = this.prev;\n    n.backtraceScore = this.backtraceScore;\n    return n;\n  }\n}\n","import { Callable } from './utils/generic';\n\nimport { reverseDictionary, escapeRegExp, isIntegralNumber, mergeArrays, len, ProgressCallback } from './utils/core';\n\nimport { getModelJSON } from './utils/hub';\n\nimport { max, min, round } from './utils/maths';\nimport { Tensor } from './utils/tensor';\n\nimport { PriorityQueue, TokenLattice, CharTrie } from './utils/data-structures';\n\nimport { Template } from '@huggingface/jinja';\nimport { PretrainedOptions } from './utils/hub';\nimport { WHISPER_LANGUAGE_MAPPING } from './models/whisper/common_whisper';\nimport { PretrainedConfig } from './configs';\n\ntype TokenizerProperties = {\n    legacy?: boolean;\n};\ntype PretrainedTokenizerOptions = PretrainedOptions & TokenizerProperties;\n/**\n * @typedef {Object} TokenizerProperties Additional tokenizer-specific properties.\n * @property {boolean} [legacy=false] Whether or not the `legacy` behavior of the tokenizer should be used.\n * @typedef {import('./utils/hub.js').PretrainedOptions & TokenizerProperties} PretrainedTokenizerOptions\n */\n\n/**\n * Loads a tokenizer from the specified path.\n * @param {string} pretrained_model_name_or_path The path to the tokenizer directory.\n * @param {PretrainedTokenizerOptions} options Additional options for loading the tokenizer.\n * @returns {Promise<any[]>} A promise that resolves with information about the loaded tokenizer.\n */\nasync function loadTokenizer(pretrained_model_name_or_path: string, options: PretrainedTokenizerOptions) {\n    const info = await Promise.all([\n        getModelJSON(pretrained_model_name_or_path, 'tokenizer.json', true, options),\n        getModelJSON(pretrained_model_name_or_path, 'tokenizer_config.json', true, options),\n    ]);\n\n    // Override legacy option if `options.legacy` is not null\n    if (options.legacy !== null) {\n        info[1].legacy = options.legacy;\n    }\n    return info;\n}\n\n/**\n * Helper function to split a string on a regex, but keep the delimiters.\n * This is required, because the JavaScript `.split()` method does not keep the delimiters,\n * and wrapping in a capturing group causes issues with existing capturing groups (due to nesting).\n * @param {string} text The text to split.\n * @param {RegExp} regex The regex to split on.\n * @returns {string[]} The split string.\n */\nfunction regexSplit(text: string, regex: RegExp) {\n    const result = [];\n    let prev = 0;\n    for (const match of text.matchAll(regex)) {\n        const fullMatch = match[0];\n        if (prev < match.index) {\n            result.push(text.slice(prev, match.index));\n        }\n        if (fullMatch.length > 0) {\n            result.push(fullMatch);\n        }\n        prev = match.index + fullMatch.length;\n    }\n    if (prev < text.length) {\n        result.push(text.slice(prev));\n    }\n    return result;\n}\n\n/**\n * Helper method to construct a pattern from a config object.\n * @param {Object} pattern The pattern object.\n * @param {boolean} invert Whether to invert the pattern.\n * @returns {RegExp|null} The compiled pattern.\n */\nfunction createPattern(pattern: { Regex: string; String: string }, invert = true) {\n    if (pattern.Regex !== undefined) {\n        // In certain cases, the pattern may contain unnecessary escape sequences (e.g., \\# or \\& or \\~).\n        // i.e., valid in Python (where the patterns are exported from) but invalid in JavaScript (where the patterns are parsed).\n        // This isn't an issue when creating the regex w/o the 'u' flag, but it is when the 'u' flag is used.\n        // For this reason, it is necessary to remove these backslashes before creating the regex.\n        // See https://stackoverflow.com/a/63007777/13989043 for more information\n        let regex = pattern.Regex.replace(/\\\\([#&~])/g, '$1'); // TODO: add more characters to this list if necessary\n\n        // We also handle special cases where the regex contains invalid (non-JS compatible) syntax.\n        for (const [key, value] of PROBLEMATIC_REGEX_MAP) {\n            regex = regex.replaceAll(key, value);\n        }\n\n        return new RegExp(regex, 'gu');\n    } else if (pattern.String !== undefined) {\n        const escaped = escapeRegExp(pattern.String);\n        // NOTE: if invert is true, we wrap the pattern in a group so that it is kept when performing .split()\n        return new RegExp(invert ? escaped : `(${escaped})`, 'gu');\n    } else {\n        console.warn('Unknown pattern type:', pattern);\n        return null;\n    }\n}\n\n/**\n * Helper function to convert an Object to a Map\n * @param {Object} obj The object to convert.\n * @returns {Map<string, any>} The map.\n */\nfunction objectToMap(obj: object) {\n    return new Map(Object.entries(obj));\n}\n\n/**\n * Helper function to convert a tensor to a list before decoding.\n * @param {Tensor} tensor The tensor to convert.\n * @returns {number[]} The tensor as a list.\n */\nfunction prepareTensorForDecode(tensor: Tensor) {\n    const dims = tensor.dims;\n    switch (dims.length) {\n        case 1:\n            return tensor.tolist();\n        case 2:\n            if (dims[0] !== 1) {\n                throw new Error(\n                    'Unable to decode tensor with `batch size !== 1`. Use `tokenizer.batch_decode(...)` for batched inputs.',\n                );\n            }\n            return tensor.tolist()[0];\n        default:\n            throw new Error(`Expected tensor to have 1-2 dimensions, got ${dims.length}.`);\n    }\n}\n\n/**\n * Clean up a list of simple English tokenization artifacts like spaces before punctuations and abbreviated forms\n * @param {string} text The text to clean up.\n * @returns {string} The cleaned up text.\n */\nfunction clean_up_tokenization(text: string) {\n    // Clean up a list of simple English tokenization artifacts\n    // like spaces before punctuations and abbreviated forms\n    return text\n        .replace(/ \\./g, '.')\n        .replace(/ \\?/g, '?')\n        .replace(/ \\!/g, '!')\n        .replace(/ ,/g, ',')\n        .replace(/ \\' /g, \"'\")\n        .replace(/ n\\'t/g, \"n't\")\n        .replace(/ \\'m/g, \"'m\")\n        .replace(/ \\'s/g, \"'s\")\n        .replace(/ \\'ve/g, \"'ve\")\n        .replace(/ \\'re/g, \"'re\");\n}\n\n/**\n * Helper function to remove accents from a string.\n * @param {string} text The text to remove accents from.\n * @returns {string} The text with accents removed.\n */\nfunction remove_accents(text: string) {\n    return text.replace(/\\p{M}/gu, '');\n}\n\n/**\n * Helper function to lowercase a string and remove accents.\n * @param {string} text The text to lowercase and remove accents from.\n * @returns {string} The lowercased text with accents removed.\n */\nfunction lowercase_and_remove_accent(text: string) {\n    return remove_accents(text.toLowerCase());\n}\n\n/**\n * Checks whether the given Unicode codepoint represents a CJK (Chinese, Japanese, or Korean) character.\n *\n * A \"chinese character\" is defined as anything in the CJK Unicode block:\n * https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)\n *\n * Note that the CJK Unicode block is NOT all Japanese and Korean characters, despite its name.\n * The modern Korean Hangul alphabet is a different block, as is Japanese Hiragana and Katakana.\n * Those alphabets are used to write space-separated words, so they are not treated specially\n * and are handled like all other languages.\n *\n * @param {number|bigint} cp The Unicode codepoint to check.\n * @returns {boolean} True if the codepoint represents a CJK character, false otherwise.\n */\nexport function is_chinese_char(cp: number | bigint) {\n    return (\n        (cp >= 0x4e00 && cp <= 0x9fff) ||\n        (cp >= 0x3400 && cp <= 0x4dbf) ||\n        (cp >= 0x20000 && cp <= 0x2a6df) ||\n        (cp >= 0x2a700 && cp <= 0x2b73f) ||\n        (cp >= 0x2b740 && cp <= 0x2b81f) ||\n        (cp >= 0x2b820 && cp <= 0x2ceaf) ||\n        (cp >= 0xf900 && cp <= 0xfaff) ||\n        (cp >= 0x2f800 && cp <= 0x2fa1f)\n    );\n}\n\n/**\n * Helper function to fuse consecutive unknown tokens.\n * @param {string[]} arr The list of input tokens\n * @param {Map<string, any>} tokens_to_ids The mapping from tokens to token ids.\n * @param {number} unk_token_id The value to fuse on.\n * @private\n */\nfunction fuse_unk(arr: string[], tokens_to_ids: Map<string, any>, unk_token_id: number) {\n    const fused = [];\n    let i = 0;\n    while (i < arr.length) {\n        fused.push(arr[i]);\n        if ((tokens_to_ids.get(arr[i]) ?? unk_token_id) !== unk_token_id) {\n            ++i;\n            continue;\n        }\n\n        while (++i < arr.length && (tokens_to_ids.get(arr[i]) ?? unk_token_id) === unk_token_id) {\n            if (tokens_to_ids.get(fused.at(-1)!) !== unk_token_id) {\n                fused[fused.length - 1] += arr[i];\n            }\n        }\n    }\n\n    return fused;\n}\n\n/**\n * Split a string on whitespace.\n * @param {string} text The text to split.\n * @returns {string[]} The split string.\n */\nfunction whitespace_split(text: string) {\n    return text.match(/\\S+/g) || [];\n}\n\nconst PUNCTUATION_REGEX = '\\\\p{P}\\\\u0021-\\\\u002F\\\\u003A-\\\\u0040\\\\u005B-\\\\u0060\\\\u007B-\\\\u007E';\nconst PUNCTUATION_ONLY_REGEX = new RegExp(`^[${PUNCTUATION_REGEX}]+$`, 'gu');\nconst BLOOM_SPLIT_CHARS = '.,!?\\u2026\\u3002\\uff0c\\u3001\\u0964\\u06d4\\u060c';\n\n// A mapping of regex patterns to their equivalent (but possibly longer) JS-compatible versions.\nconst PROBLEMATIC_REGEX_MAP = new Map([\n    // This uses the case insensitive group modifier, which is not supported in JavaScript.\n    // When parsing the regex, an \"Invalid group\" error is thrown.\n    [\"(?i:'s|'t|'re|'ve|'m|'ll|'d)\", \"(?:'([sS]|[tT]|[rR][eE]|[vV][eE]|[mM]|[lL][lL]|[dD]))\"],\n\n    // Used to override the default (invalid) regex of the bloom pretokenizer.\n    // For more information, see https://github.com/huggingface/transformers.js/issues/94\n    [` ?[^(\\\\s|[${BLOOM_SPLIT_CHARS}])]+`, ` ?[^\\\\s${BLOOM_SPLIT_CHARS}]+`],\n]);\n\n/**\n * Represent a token added by the user on top of the existing Model vocabulary.\n * AddedToken can be configured to specify the behavior they should have in various situations like:\n *   - Whether they should only match single words\n *   - Whether to include any whitespace on its left or right\n */\nclass AddedToken {\n    /**\n     * Creates a new instance of AddedToken.\n     * @param {Object} config Added token configuration object.\n     * @param {string} config.content The content of the added token.\n     * @param {number} config.id The id of the added token.\n     * @param {boolean} [config.single_word=false] Whether this token must be a single word or can break words.\n     * @param {boolean} [config.lstrip=false] Whether this token should strip whitespaces on its left.\n     * @param {boolean} [config.rstrip=false] Whether this token should strip whitespaces on its right.\n     * @param {boolean} [config.normalized=false] Whether this token should be normalized.\n     * @param {boolean} [config.special=false] Whether this token is special.\n     */\n    content: string;\n    id: number;\n    single_word?: boolean;\n    lstrip?: boolean;\n    rstrip?: boolean;\n    special?: boolean;\n    normalized?: boolean;\n    constructor(config: {\n        content: string;\n        id: number;\n        single_word?: boolean;\n        lstrip?: boolean;\n        rstrip?: boolean;\n        special?: boolean;\n        normalized?: boolean;\n    }) {\n        this.content = config.content;\n        this.id = config.id;\n        this.single_word = config.single_word ?? false;\n        this.lstrip = config.lstrip ?? false;\n        this.rstrip = config.rstrip ?? false;\n        this.special = config.special ?? false;\n        this.normalized = config.normalized ?? false;\n    }\n}\n\n/**\n * Abstract base class for tokenizer models.\n *\n * @extends Callable\n */\nexport class TokenizerModel extends Callable {\n    /**\n     * Creates a new instance of TokenizerModel.\n     * @param {Object} config The configuration object for the TokenizerModel.\n     */\n    vocab: string[];\n    tokens_to_ids: Map<string, number>;\n    unk_token_id: number | undefined;\n    unk_token: string | undefined;\n    end_of_word_suffix: string | undefined;\n    fuse_unk: boolean;\n    config: {\n        vocab: string[];\n        tokens_to_ids: Map<string, number>;\n        unk_token_id: number | undefined;\n        unk_token: string | undefined;\n        end_of_word_suffix: string | undefined;\n        fuse_unk: boolean;\n    };\n\n    constructor(config: {\n        vocab: string[];\n        tokens_to_ids: Map<string, number>;\n        unk_token_id: number | undefined;\n        unk_token: string | undefined;\n        end_of_word_suffix: string | undefined;\n        fuse_unk: boolean;\n    }) {\n        super();\n        this.config = config;\n\n        /** @type {string[]} */\n        this.vocab = [];\n\n        /**\n         * A mapping of tokens to ids.\n         * @type {Map<string, number>}\n         */\n        this.tokens_to_ids = new Map();\n\n        this.unk_token_id = undefined;\n        this.unk_token = undefined;\n        this.end_of_word_suffix = undefined;\n\n        /** @type {boolean} Whether to fuse unknown tokens when encoding. Defaults to false. */\n        this.fuse_unk = this.config.fuse_unk ?? false;\n    }\n\n    /**\n     * Instantiates a new TokenizerModel instance based on the configuration object provided.\n     * @param {Object} config The configuration object for the TokenizerModel.\n     * @param {...*} args Optional arguments to pass to the specific TokenizerModel constructor.\n     * @returns {TokenizerModel} A new instance of a TokenizerModel.\n     * @throws Will throw an error if the TokenizerModel type in the config is not recognized.\n     */\n    static fromConfig(\n        config: {\n            type: string;\n            vocab: string[];\n            tokens_to_ids: Map<string, number>;\n            unk_token_id: number | undefined;\n            unk_token: string | undefined;\n            end_of_word_suffix: string | undefined;\n            fuse_unk: boolean;\n        },\n        ...args: any[]\n    ) {\n        switch (config.type) {\n            case 'WordPiece':\n                return new WordPieceTokenizer(config);\n            case 'Unigram':\n                // @ts-ignore\n                return new Unigram(config, ...args);\n            case 'BPE':\n                return new BPE(config as any);\n\n            default:\n                // Some tokenizers, like for google-t5/t5-small, do not have a `type` field.\n                // In this case, we can infer the tokenizer type based on the structure of the `vocab` field.\n                if (config.vocab) {\n                    if (Array.isArray(config.vocab)) {\n                        // config.vocab is of type `[string, number][]`\n                        // @ts-ignore\n                        return new Unigram(config, ...args);\n                    } else {\n                        // @ts-ignore\n                        return new LegacyTokenizerModel(config, ...args);\n                    }\n                }\n                throw new Error(`Unknown TokenizerModel type: ${config.type}`);\n        }\n    }\n\n    /**\n     * Internal function to call the TokenizerModel instance.\n     * @param {string[]} tokens The tokens to encode.\n     * @returns {string[]} The encoded tokens.\n     */\n    _call(tokens: string[]) {\n        tokens = this.encode(tokens);\n        if (this.fuse_unk) {\n            // Fuse unknown tokens\n            tokens = fuse_unk(tokens, this.tokens_to_ids, this.unk_token_id!);\n        }\n        return tokens;\n    }\n\n    /**\n     * Encodes a list of tokens into a list of token IDs.\n     * @param {string[]} tokens The tokens to encode.\n     * @returns {string[]} The encoded tokens.\n     * @throws Will throw an error if not implemented in a subclass.\n     */\n    encode(tokens: string[]): string[] {\n        throw Error('encode should be implemented in subclass.');\n    }\n\n    /**\n     * Converts a list of tokens into a list of token IDs.\n     * @param {string[]} tokens The tokens to convert.\n     * @returns {number[]} The converted token IDs.\n     */\n    convert_tokens_to_ids(tokens: string[]) {\n        return tokens.map((t) => this.tokens_to_ids.get(t) ?? this.unk_token_id);\n    }\n\n    /**\n     * Converts a list of token IDs into a list of tokens.\n     * @param {number[]|bigint[]} ids The token IDs to convert.\n     * @returns {string[]} The converted tokens.\n     */\n    convert_ids_to_tokens(ids: number[] | bigint[]) {\n        return ids.map((i: number | bigint) => this.vocab[i as number] ?? this.unk_token);\n    }\n}\n\n/**\n * A subclass of TokenizerModel that uses WordPiece encoding to encode tokens.\n * @extends TokenizerModel\n */\nclass WordPieceTokenizer extends TokenizerModel {\n    /**\n     * @param {Object} config The configuration object.\n     * @param {Object} config.vocab A mapping of tokens to ids.\n     * @param {string} config.unk_token The unknown token string.\n     * @param {string} config.continuing_subword_prefix The prefix to use for continuing subwords.\n     * @param {number} [config.max_input_chars_per_word=100] The maximum number of characters per word.\n     */\n    max_input_chars_per_word: number;\n    constructor(config: any) {\n        super(config as any);\n        /**\n         * A mapping of tokens to ids.\n         * @type {Map<string, number>}\n         */\n        this.tokens_to_ids = objectToMap(config.vocab);\n\n        /**\n         * The id of the unknown token.\n         * @type {number}\n         */\n        this.unk_token_id = this.tokens_to_ids.get(config.unk_token);\n\n        /**\n         * The unknown token string.\n         * @type {string}\n         */\n        this.unk_token = config.unk_token;\n\n        /**\n         * The maximum number of characters allowed per word.\n         * @type {number}\n         */\n        this.max_input_chars_per_word = config.max_input_chars_per_word ?? 100;\n\n        /**\n         * An array of tokens.\n         * @type {string[]}\n         */\n        this.vocab = new Array(this.tokens_to_ids.size);\n        for (const [key, value] of this.tokens_to_ids) {\n            this.vocab[value] = key;\n        }\n    }\n\n    /**\n     * Encodes an array of tokens using WordPiece encoding.\n     * @param {string[]} tokens The tokens to encode.\n     * @returns {string[]} An array of encoded tokens.\n     */\n    encode(tokens: string[]): string[] {\n        const outputTokens: string[] = [];\n        for (const token of tokens) {\n            const chars = [...token];\n            if (chars.length > this.max_input_chars_per_word) {\n                outputTokens.push(this.unk_token as string);\n                continue;\n            }\n\n            let isUnknown = false;\n            let start = 0;\n            const subTokens = [];\n\n            while (start < chars.length) {\n                let end = chars.length;\n                let currentSubstring = null;\n                while (start < end) {\n                    let substr = chars.slice(start, end).join('');\n\n                    if (start > 0) {\n                        substr = (this as any).config.continuing_subword_prefix + substr;\n                    }\n                    if (this.tokens_to_ids.has(substr)) {\n                        currentSubstring = substr;\n                        break;\n                    }\n\n                    --end;\n                }\n                if (currentSubstring === null) {\n                    isUnknown = true;\n                    break;\n                }\n                subTokens.push(currentSubstring);\n                start = end;\n            }\n            if (isUnknown) {\n                outputTokens.push(this.unk_token as string);\n            } else {\n                outputTokens.push(...subTokens);\n            }\n        }\n\n        return outputTokens;\n    }\n}\n\n/**\n * Class representing a Unigram tokenizer model.\n * @extends TokenizerModel\n */\nclass Unigram extends TokenizerModel {\n    /**\n     * Create a new Unigram tokenizer model.\n     * @param {Object} config The configuration object for the Unigram model.\n     * @param {number} config.unk_id The ID of the unknown token\n     * @param {[string, number][]} config.vocab A 2D array representing a mapping of tokens to scores.\n     * @param {Object} moreConfig Additional configuration object for the Unigram model.\n     */\n    unk_token_id: number | undefined;\n    scores: number[];\n    bos_token: string;\n    eos_token: string;\n    bos_token_id: number | undefined;\n    eos_token_id: number | undefined;\n    minScore: number | BigInt;\n    unk_score: number | BigInt;\n    trie: CharTrie;\n    fuse_unk: boolean;\n\n    constructor(\n        config: {\n            unk_id: number;\n            vocab: [string, number][];\n        },\n        moreConfig: {\n            eos_token: string;\n        },\n    ) {\n        super(config as any);\n\n        const vocabSize = config.vocab.length;\n        this.vocab = new Array(vocabSize);\n        /** @type {number[]} */\n        this.scores = new Array(vocabSize);\n        for (let i = 0; i < vocabSize; ++i) {\n            [this.vocab[i], this.scores[i]] = config.vocab[i];\n        }\n\n        this.unk_token_id = config.unk_id;\n        this.unk_token = this.vocab[config.unk_id];\n\n        this.tokens_to_ids = new Map(this.vocab.map((x, i) => [x, i]));\n        this.bos_token = ' '; // beginning of a sentence token\n\n        this.bos_token_id = this.tokens_to_ids.get(this.bos_token); // NOTE: may be undefined\n        this.eos_token = moreConfig.eos_token;\n\n        this.eos_token_id = this.tokens_to_ids.get(this.eos_token);\n        this.unk_token = this.vocab[this.unk_token_id];\n\n        this.minScore = min(this.scores)[0];\n\n        this.unk_score = Number(this.minScore) - 10.0;\n        this.scores[this.unk_token_id] = this.unk_score;\n\n        this.trie = new CharTrie();\n        this.trie.extend(this.vocab);\n\n        // NOTE: `fuse_unk` is hardcoded to true for Unigram models\n        // See: https://github.com/huggingface/tokenizers/blob/b58227c7f1ccf8b73ee2268354336da56d91e492/tokenizers/src/models/unigram/model.rs#L119\n        this.fuse_unk = true;\n    }\n\n    /**\n     * Populates lattice nodes.\n     * @param {TokenLattice} lattice The token lattice to populate with nodes.\n     */\n    populateNodes(lattice: TokenLattice) {\n        const chars = lattice._chars;\n        const mblen = 1;\n        let beginPos = 0;\n        while (beginPos < chars.length) {\n            let hasSingleNode = false;\n\n            const tokens = [];\n            const sliced = chars.slice(beginPos).join('');\n            const prefixedTokens = this.trie.commonPrefixSearch(sliced);\n            for (const token of prefixedTokens) {\n                tokens.push(token);\n                const tokenId = this.tokens_to_ids.get(token);\n                const tokenScore = this.scores[tokenId as number];\n                const n = len(token);\n                lattice.insert(beginPos, n, tokenScore, tokenId as number);\n                if (!hasSingleNode && n === mblen) {\n                    hasSingleNode = true;\n                }\n            }\n            if (!hasSingleNode) {\n                lattice.insert(beginPos, mblen, Number(this.unk_score), this.unk_token_id as number);\n            }\n            beginPos += mblen;\n        }\n    }\n\n    /**\n     * Encodes an array of tokens into an array of subtokens using the unigram model.\n     *\n     * @param {string} normalized The normalized string.\n     * @returns {string[]} An array of subtokens obtained by encoding the input tokens using the unigram model.\n     */\n    tokenize(normalized: string) {\n        const lattice = new TokenLattice(normalized, this.bos_token_id as number, this.eos_token_id as number);\n        this.populateNodes(lattice);\n        return lattice.tokens();\n    }\n\n    /**\n     * Encodes an array of tokens using Unigram encoding.\n     * @param {string[]} tokens The tokens to encode.\n     * @returns {string[]} An array of encoded tokens.\n     */\n    encode(tokens: string[]) {\n        const toReturn = [];\n        for (const token of tokens) {\n            const tokenized = this.tokenize(token);\n            toReturn.push(...tokenized);\n        }\n        return toReturn;\n    }\n}\n\n/**\n * Returns list of utf-8 byte and a mapping to unicode strings.\n * Specifically avoids mapping to whitespace/control characters the BPE code barfs on.\n * @returns {Object} Object with utf-8 byte keys and unicode string values.\n */\nconst BYTES_TO_UNICODE = (() => {\n    // Returns list of utf-8 byte and a mapping to unicode strings.\n    // We specifically avoids mapping to whitespace/control characters\n    // the bpe code barfs on.\n\n    const bs = [\n        ...Array.from({ length: '~'.charCodeAt(0) - '!'.charCodeAt(0) + 1 }, (_, i) => i + '!'.charCodeAt(0)),\n        ...Array.from({ length: '¬'.charCodeAt(0) - '¡'.charCodeAt(0) + 1 }, (_, i) => i + '¡'.charCodeAt(0)),\n        ...Array.from({ length: 'ÿ'.charCodeAt(0) - '®'.charCodeAt(0) + 1 }, (_, i) => i + '®'.charCodeAt(0)),\n    ];\n    const cs = bs.slice();\n    let n = 0;\n    for (let b = 0; b < 256; ++b) {\n        if (!bs.includes(b)) {\n            bs.push(b);\n            cs.push(256 + n);\n            n += 1;\n        }\n    }\n    const ccs = cs.map((n) => String.fromCharCode(n));\n    return Object.fromEntries(bs.map((b, i) => [b, ccs[i]]));\n})();\n\nconst UNICODE_TO_BYTES = reverseDictionary(BYTES_TO_UNICODE);\n\n/**\n * @typedef {Object} BPENode\n * @property {string} token The token associated with the node\n * @property {number} bias A positional bias for the node.\n * @property {number} [score] The score of the node.\n * @property {BPENode} [prev] The previous node in the linked list.\n * @property {BPENode} [next] The next node in the linked list.\n */\n\n/**\n * BPE class for encoding text into Byte-Pair-Encoding (BPE) tokens.\n * @extends TokenizerModel\n */\nclass BPE extends TokenizerModel {\n    /**\n     * Create a BPE instance.\n     * @param {Object} config The configuration object for BPE.\n     * @param {Object} config.vocab A mapping of tokens to ids.\n     * @param {string[]|[string, string][]} config.merges An array of BPE merges as strings.\n     * @param {string} config.unk_token The unknown token used for out of vocabulary words.\n     * @param {string} config.end_of_word_suffix The suffix to place at the end of each word.\n     * @param {string} [config.continuing_subword_suffix] The suffix to insert between words.\n     * @param {boolean} [config.byte_fallback=false] Whether to use spm byte-fallback trick (defaults to False)\n     * @param {boolean} [config.ignore_merges=false] Whether or not to match tokens with the vocab before using merges.\n     */\n    ignore_merges: boolean;\n    merges: [string, string][];\n    bpe_ranks: Map<string, number>;\n    end_of_word_suffix: string;\n    continuing_subword_suffix: string | null;\n    byte_fallback: boolean;\n    cache: Map<string, string[]>;\n    text_encoder: any;\n    constructor(config: {\n        vocab: string[];\n        merges: string[] | [string, string][];\n        unk_token: string;\n        end_of_word_suffix: string;\n        continuing_subword_suffix?: string;\n        byte_fallback?: boolean;\n        ignore_merges?: boolean;\n    }) {\n        super(config as any);\n\n        /** @type {Map<string, number>} */\n        this.tokens_to_ids = objectToMap(config.vocab);\n\n        this.unk_token_id = this.tokens_to_ids.get(config.unk_token);\n        this.unk_token = config.unk_token;\n\n        this.vocab = new Array(this.tokens_to_ids.size);\n        for (const [key, value] of this.tokens_to_ids) {\n            this.vocab[value] = key;\n        }\n\n        // Tokenizers >= 0.20.0 serializes BPE merges as a [string, string][] instead of a string[],\n        // which resolves the ambiguity for merges containing spaces.\n        const use_new_merge_format = Array.isArray(config.merges[0]);\n\n        /** @type {[string, string][]} */\n        this.merges = use_new_merge_format\n            ? /** @type {[string, string][]} */ config.merges\n            : config/** @type {string[]} */.merges\n                .map((x) => /** @type {[string, string]} */(x as any).split(' ', 2));\n        this.bpe_ranks = new Map(this.merges.map((x, i) => [JSON.stringify(x), i]));\n\n        this.end_of_word_suffix = config.end_of_word_suffix;\n\n        // NOTE: `continuing_subword_suffix` is custom (to support `BlenderbotSmallTokenizer`)\n        this.continuing_subword_suffix = config.continuing_subword_suffix ?? null;\n\n        this.byte_fallback = (this.config as any).byte_fallback ?? false;\n\n        if (this.byte_fallback) {\n            this.text_encoder = new TextEncoder();\n        }\n\n        this.ignore_merges = (this as any).config.ignore_merges ?? false;\n\n        /** @type {Map<string, string[]>} */\n        this.cache = new Map();\n    }\n\n    /**\n     * Apply Byte-Pair-Encoding (BPE) to a given token. Efficient heap-based priority\n     * queue implementation adapted from https://github.com/belladoreai/llama-tokenizer-js.\n     * @param {string} token The token to encode.\n     * @returns {string[]} The BPE encoded tokens.\n     */\n    bpe(token: string) {\n        if (token.length === 0) {\n            return [];\n        }\n\n        const cached = (this as any).cache.get(token);\n        if (cached !== undefined) {\n            return cached;\n        }\n\n        const word = Array.from(token);\n        if (this.end_of_word_suffix) {\n            word[word.length - 1] += this.end_of_word_suffix;\n        }\n\n        let result = [];\n        if (word.length > 1) {\n            // Create a priority queue to store the nodes that will be merged.\n            // The comparator function compares the scores of the nodes.\n            const queue = new PriorityQueue((a, b) => a.score < b.score);\n\n            // Construct a doubly-linked list of nodes that will be inserted into the priority queue,\n            // starting with the individual characters. We also populate each node with a positional\n            // bias to break ties in the priority queue.\n            let startingNode = {\n                token: word[0],\n                bias: 0,\n                prev: null,\n                next: null,\n            };\n\n            let previousNode: any = startingNode;\n            for (let i = 1; i < word.length; ++i) {\n                const currentNode = {\n                    bias: i / word.length, // Add fractional component to break ties\n                    token: word[i],\n                    prev: previousNode,\n                    next: null,\n                };\n                previousNode.next = currentNode;\n                this._add_node(queue, previousNode);\n                previousNode = currentNode;\n            }\n\n            while (!queue.isEmpty()) {\n                // Get the next node with the highest priority\n                const node = queue.pop();\n\n                // Check that this merge is still possible\n                if (node.deleted || !node.next || node.next.deleted) continue;\n\n                // Here, we mark the current node (left side of the merge) and the next node (right side of the merge) as deleted.\n                // This is because they will both be replaced by a new node representing the merge result.\n                node.deleted = true;\n                node.next.deleted = true;\n\n                // Next, we fix the node that comes before the current node (i.e., left side of the merge).\n                if (node.prev) {\n                    // Make a shallow copy of the previous node\n                    const newPreviousNode = { ...node.prev };\n\n                    // Mark the old previous node as deleted. This avoids erroneous merges later,\n                    // because there may still be references to this node in the priority queue.\n                    node.prev.deleted = true;\n                    node.prev = newPreviousNode;\n\n                    // Update the reference of the previous node, by pointing its previous node to this new previous node.\n                    if (newPreviousNode.prev) {\n                        newPreviousNode.prev.next = newPreviousNode;\n                    } else {\n                        // If the previous of the previous node does not exist, it means that\n                        // `newPreviousNode` must be the new `startingNode`.\n                        startingNode = newPreviousNode;\n                    }\n                }\n\n                // Create a new node which represents the result of the merge.\n                const merged = {\n                    token: node.token + node.next.token,\n                    bias: node.bias,\n                    prev: node.prev,\n                    next: node.next.next,\n                };\n\n                // We now consider where we can add the new merged node to the priority queue:\n                // 1. prev <-> merged\n                if (merged.prev) {\n                    merged.prev.next = merged;\n                    this._add_node(queue, merged.prev);\n                } else {\n                    // If `merged.prev` does not exist, then `merged` must be the new `startingNode`.\n                    startingNode = merged;\n                }\n\n                // 2. merged <-> next\n                if (merged.next) {\n                    merged.next.prev = merged;\n                    this._add_node(queue, merged);\n                }\n            }\n\n            // Traverse the linked list, starting from the `startingNode`, and collect the tokens.\n            for (let currentNode: any = startingNode; currentNode !== null; currentNode = currentNode.next) {\n                result.push(currentNode.token);\n            }\n        } else {\n            result = word;\n        }\n\n        // Possibly append suffix\n        if (this.continuing_subword_suffix) {\n            // Do not append suffix to the last token\n            for (let i = 0; i < result.length - 1; ++i) {\n                result[i] += this.continuing_subword_suffix;\n            }\n        }\n\n        // Save the result to the cache\n        this.cache.set(token, result);\n\n        return result;\n    }\n\n    /**\n     * Helper function to add a node to the priority queue.\n     * @param {PriorityQueue} queue\n     * @param {BPENode} node\n     * @private\n     */\n    _add_node(queue: any, node: any) {\n        // `score` is a measure of the merge priority: lower means higher priority\n        // We use the BPE rank as a measure of priority (i.e., the local of the merge in the merges list)\n        // We also add a fractional component to the score to break ties (with the earlier character having higher priority)\n        const rank = this.bpe_ranks.get(JSON.stringify([node.token, node.next.token]));\n        if (rank !== undefined) {\n            node.score = rank + node.bias;\n            queue.push(node);\n        }\n    }\n\n    /**\n     * Encodes the input sequence of tokens using the BPE algorithm and returns the resulting subword tokens.\n     * @param {string[]} tokens The input sequence of tokens to encode.\n     * @returns {string[]} The resulting subword tokens after applying the BPE algorithm to the input sequence of tokens.\n     */\n    encode(tokens: string[]) {\n        const outputTokens = [];\n\n        for (const token of tokens) {\n            if (this.ignore_merges && this.tokens_to_ids.has(token)) {\n                outputTokens.push(token);\n                continue;\n            }\n            const bpe_token_list = this.bpe(token);\n\n            for (const t of bpe_token_list) {\n                if (this.tokens_to_ids.has(t)) {\n                    outputTokens.push(t);\n                } else if (this.byte_fallback) {\n                    const byteTokens = Array.from(this.text_encoder.encode(t)).map(\n                        (x: any) => `<0x${x.toString(16).toUpperCase().padStart(2, '0')}>`,\n                    );\n                    if (byteTokens.every((x) => this.tokens_to_ids.has(x))) {\n                        // Ensure the byte tokens are actually in the vocabulary, otherwise\n                        // we fall back to the unknown token. For more information, see\n                        // https://github.com/huggingface/transformers/issues/28096.\n                        outputTokens.push(...byteTokens);\n                    } else {\n                        outputTokens.push(this.unk_token);\n                    }\n                } else {\n                    outputTokens.push(this.unk_token);\n                }\n            }\n        }\n\n        return outputTokens;\n    }\n}\n\n/**\n * Legacy tokenizer class for tokenizers with only a vocabulary.\n */\nclass LegacyTokenizerModel extends TokenizerModel {\n    /**\n     * Create a LegacyTokenizerModel instance.\n     * @param {Object} config The configuration object for LegacyTokenizerModel.\n     * @param {Object} config.vocab A (possibly nested) mapping of tokens to ids.\n     * @param {Object} moreConfig Additional configuration object for the LegacyTokenizerModel model.\n     */\n    bos_token: string;\n    eos_token: string;\n    pad_token: string;\n    unk_token: string;\n    bos_token_id: number | undefined;\n    eos_token_id: number | undefined;\n    pad_token_id: number | undefined;\n    unk_token_id: number | undefined;\n    vocab: string[];\n    constructor(\n        config: {\n            vocab: string[];\n            target_lang?: string;\n        },\n        moreConfig: {\n            bos_token: string;\n            eos_token: string;\n            target_lang?: any;\n            pad_token?: any;\n            unk_token?: any;\n        },\n    ) {\n        super(config as any);\n\n        /**@type {Map<string, number>} */\n        this.tokens_to_ids = objectToMap(\n            (moreConfig.target_lang ? config.vocab[moreConfig.target_lang] : config.vocab) as any,\n        );\n\n        this.bos_token = moreConfig.bos_token;\n        this.bos_token_id = this.tokens_to_ids.get(this.bos_token);\n\n        this.eos_token = moreConfig.eos_token;\n        this.eos_token_id = this.tokens_to_ids.get(this.eos_token);\n\n        this.pad_token = moreConfig.pad_token;\n        this.pad_token_id = this.tokens_to_ids.get(this.pad_token);\n\n        this.unk_token = moreConfig.unk_token;\n        this.unk_token_id = this.tokens_to_ids.get(this.unk_token);\n\n        this.vocab = new Array(this.tokens_to_ids.size);\n        for (const [key, value] of this.tokens_to_ids) {\n            this.vocab[value] = key;\n        }\n    }\n\n    encode(tokens: string[]) {\n        return tokens;\n    }\n}\n\n/**\n * A base class for text normalization.\n * @abstract\n */\nclass Normalizer extends Callable {\n    /**\n     * @param {Object} config The configuration object for the normalizer.\n     */\n    config: any;\n    constructor(config: { type: string }) {\n        super();\n        this.config = config;\n    }\n\n    /**\n     * Factory method for creating normalizers from config objects.\n     * @static\n     * @param {Object} config The configuration object for the normalizer.\n     * @returns {Normalizer} A Normalizer object.\n     * @throws {Error} If an unknown Normalizer type is specified in the config.\n     */\n    static fromConfig(config: { type: string }) {\n        if (config === null) return null;\n        switch (config.type) {\n            case 'BertNormalizer':\n                return new BertNormalizer(config);\n            case 'Precompiled':\n                return new Precompiled(config);\n            case 'Sequence':\n                return new NormalizerSequence(config as any);\n            case 'Replace':\n                return new Replace(config);\n            case 'NFC':\n                return new NFC(config);\n            case 'NFKC':\n                return new NFKC(config);\n            case 'NFKD':\n                return new NFKD(config);\n            case 'Strip':\n                return new StripNormalizer(config);\n            case 'StripAccents':\n                return new StripAccents(config);\n            case 'Lowercase':\n                return new Lowercase(config);\n            case 'Prepend':\n                return new Prepend(config);\n            default:\n                throw new Error(`Unknown Normalizer type: ${config.type}`);\n        }\n    }\n\n    /**\n     * Normalize the input text.\n     * @abstract\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     * @throws {Error} If this method is not implemented in a subclass.\n     */\n    normalize(text: string) {\n        throw Error('normalize should be implemented in subclass.');\n    }\n\n    /**\n     * Alias for {@link Normalizer#normalize}.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    _call(text: string) {\n        return this.normalize(text);\n    }\n}\n\n/**\n * Replace normalizer that replaces occurrences of a pattern with a given string or regular expression.\n * @extends Normalizer\n */\nclass Replace extends Normalizer {\n    /**\n     * Normalize the input text by replacing the pattern with the content.\n     * @param {string} text The input text to be normalized.\n     * @returns {string} The normalized text after replacing the pattern with the content.\n     */\n    normalize(text: string) {\n        const pattern = createPattern(this.config.pattern);\n        return pattern === null ? text : text.replaceAll(pattern, this.config.content);\n    }\n}\n\n/**\n * A normalizer that applies Unicode normalization form C (NFC) to the input text.\n * @extends Normalizer\n */\nclass NFC extends Normalizer {\n    /**\n     * Normalize the input text by applying Unicode normalization form C (NFC).\n     * @param {string} text The input text to be normalized.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        text = text.normalize('NFC');\n        return text;\n    }\n}\n\n/**\n * NFKC Normalizer.\n * @extends Normalizer\n */\nclass NFKC extends Normalizer {\n    /**\n     * Normalize text using NFKC normalization.\n     * @param {string} text The text to be normalized.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        text = text.normalize('NFKC');\n        return text;\n    }\n}\n/**\n * NFKD Normalizer.\n * @extends Normalizer\n */\nclass NFKD extends Normalizer {\n    /**\n     * Normalize text using NFKD normalization.\n     * @param {string} text The text to be normalized.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        text = text.normalize('NFKD');\n        return text;\n    }\n}\n\n\n/**\n * A normalizer that strips leading and/or trailing whitespace from the input text.\n */\nclass StripNormalizer extends Normalizer {\n    /**\n     * Strip leading and/or trailing whitespace from the input text.\n     * @param {string} text The input text.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        if (this.config.strip_left && this.config.strip_right) {\n            // Fast path to avoid an extra trim call\n            text = text.trim();\n        } else {\n            if (this.config.strip_left) {\n                text = text.trimStart();\n            }\n            if (this.config.strip_right) {\n                text = text.trimEnd();\n            }\n        }\n        return text;\n    }\n}\n\n/**\n * StripAccents normalizer removes all accents from the text.\n * @extends Normalizer\n */\nclass StripAccents extends Normalizer {\n    /**\n     * Remove all accents from the text.\n     * @param {string} text The input text.\n     * @returns {string} The normalized text without accents.\n     */\n    normalize(text: string) {\n        text = remove_accents(text);\n        return text;\n    }\n}\n\n/**\n * A Normalizer that lowercases the input string.\n * @extends Normalizer\n */\nclass Lowercase extends Normalizer {\n    /**\n     * Lowercases the input string.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        text = text.toLowerCase();\n        return text;\n    }\n}\n\n/**\n * A Normalizer that prepends a string to the input string.\n * @extends Normalizer\n */\nclass Prepend extends Normalizer {\n    /**\n     * Prepends the input string.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        text = this.config.prepend + text;\n        return text;\n    }\n}\n\n/**\n * A Normalizer that applies a sequence of Normalizers.\n * @extends Normalizer\n */\nclass NormalizerSequence extends Normalizer {\n    /**\n     * Create a new instance of NormalizerSequence.\n     * @param {Object} config The configuration object.\n     * @param {Object[]} config.normalizers An array of Normalizer configuration objects.\n     */\n    normalizers: any;\n    constructor(config: {\n        normalizers: {\n            type: string;\n        }[];\n    }) {\n        super(config as any);\n        this.normalizers = config.normalizers.map((x: any) => Normalizer.fromConfig(x));\n    }\n    /**\n     * Apply a sequence of Normalizers to the input text.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        return this.normalizers.reduce((t: string, normalizer: any) => {\n            return normalizer.normalize(t);\n        }, text);\n    }\n}\n\n/**\n * A class representing a normalizer used in BERT tokenization.\n * @extends Normalizer\n */\nclass BertNormalizer extends Normalizer {\n    /**\n     * Adds whitespace around any CJK (Chinese, Japanese, or Korean) character in the input text.\n     *\n     * @param {string} text The input text to tokenize.\n     * @returns {string} The tokenized text with whitespace added around CJK characters.\n     */\n    _tokenize_chinese_chars(text: string) {\n        /* Adds whitespace around any CJK character. */\n        const output = [];\n        for (let i = 0; i < text.length; ++i) {\n            const char = text[i];\n            const cp = char.charCodeAt(0);\n            if (is_chinese_char(cp)) {\n                output.push(' ');\n                output.push(char);\n                output.push(' ');\n            } else {\n                output.push(char);\n            }\n        }\n        return output.join('');\n    }\n\n    /**\n     * Strips accents from the given text.\n     * @param {string} text The text to strip accents from.\n     * @returns {string} The text with accents removed.\n     */\n    stripAccents(text: string) {\n        // \"Mark, Nonspacing\" (Mn)\n        return text.normalize('NFD').replace(/\\p{Mn}/gu, '');\n    }\n\n    /**\n     * Checks whether `char` is a control character.\n     * @param {string} char The character to check.\n     * @returns {boolean} Whether `char` is a control character.\n     * @private\n     */\n    _is_control(char: string) {\n        switch (char) {\n            case '\\t':\n            case '\\n':\n            case '\\r':\n                // These are technically control characters but we count them as whitespace characters.\n                return false;\n\n            default:\n                // Check if unicode category starts with C:\n                // Cc - Control\n                // Cf - Format\n                // Co - Private Use\n                // Cs - Surrogate\n                return /^\\p{Cc}|\\p{Cf}|\\p{Co}|\\p{Cs}$/u.test(char);\n        }\n    }\n\n    /**\n     * Performs invalid character removal and whitespace cleanup on text.\n     * @param {string} text The text to clean.\n     * @returns {string} The cleaned text.\n     * @private\n     */\n    _clean_text(text: string) {\n        const output = [];\n        for (const char of text) {\n            const cp = char.charCodeAt(0);\n            if (cp === 0 || cp === 0xfffd || this._is_control(char)) {\n                continue;\n            }\n            if (/^\\s$/.test(char)) {\n                // is whitespace\n                output.push(' ');\n            } else {\n                output.push(char);\n            }\n        }\n        return output.join('');\n    }\n    /**\n     * Normalizes the given text based on the configuration.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        if (this.config.clean_text) {\n            text = this._clean_text(text);\n        }\n\n        if (this.config.handle_chinese_chars) {\n            text = this._tokenize_chinese_chars(text);\n        }\n\n        if (this.config.lowercase) {\n            text = text.toLowerCase();\n\n            if (this.config.strip_accents !== false) {\n                text = this.stripAccents(text);\n            }\n        } else if (this.config.strip_accents) {\n            text = this.stripAccents(text);\n        }\n\n        return text;\n    }\n}\n\n/**\n * A callable class representing a pre-tokenizer used in tokenization. Subclasses\n * should implement the `pre_tokenize_text` method to define the specific pre-tokenization logic.\n * @extends Callable\n */\nclass PreTokenizer extends Callable {\n    /**\n     * Factory method that returns an instance of a subclass of `PreTokenizer` based on the provided configuration.\n     *\n     * @static\n     * @param {Object} config A configuration object for the pre-tokenizer.\n     * @returns {PreTokenizer} An instance of a subclass of `PreTokenizer`.\n     * @throws {Error} If the provided configuration object does not correspond to any known pre-tokenizer.\n     */\n    static fromConfig(config: any) {\n        if (config === null) return null;\n\n        switch (config.type) {\n            case 'BertPreTokenizer':\n                return new BertPreTokenizer(config);\n            case 'Sequence':\n                return new PreTokenizerSequence(config);\n            case 'Whitespace':\n                return new WhitespacePreTokenizer(config);\n            case 'WhitespaceSplit':\n                return new WhitespaceSplit(config);\n            case 'Metaspace':\n                return new MetaspacePreTokenizer(config);\n\n            case 'ByteLevel':\n                return new ByteLevelPreTokenizer(config);\n            case 'Split':\n                return new SplitPreTokenizer(config);\n            case 'Punctuation':\n                return new PunctuationPreTokenizer(config);\n            case 'Digits':\n                return new DigitsPreTokenizer(config);\n            case 'Replace':\n                return new ReplacePreTokenizer(config);\n            default:\n                throw new Error(`Unknown PreTokenizer type: ${config.type}`);\n        }\n    }\n\n    /**\n     * Method that should be implemented by subclasses to define the specific pre-tokenization logic.\n     *\n     * @abstract\n     * @param {string} text The text to pre-tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} The pre-tokenized text.\n     * @throws {Error} If the method is not implemented in the subclass.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        throw Error('pre_tokenize_text should be implemented in subclass.');\n    }\n\n    /**\n     * Tokenizes the given text into pre-tokens.\n     * @param {string|string[]} text The text or array of texts to pre-tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of pre-tokens.\n     */\n    pre_tokenize(text: string | string[], options: any) {\n        return (\n            Array.isArray(text) ? text.map((x) => this.pre_tokenize_text(x, options)) : [this.pre_tokenize_text(text, options)]\n        ).flat();\n    }\n\n    /**\n     * Alias for {@link PreTokenizer#pre_tokenize}.\n     * @param {string|string[]} text The text or array of texts to pre-tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of pre-tokens.\n     */\n    _call(text: string | string[], options: any) {\n        return this.pre_tokenize(text, options);\n    }\n}\n\n/**\n * @extends PreTokenizer\n */\nclass BertPreTokenizer extends PreTokenizer {\n    /**\n     * A PreTokenizer that splits text into wordpieces using a basic tokenization scheme\n     * similar to that used in the original implementation of BERT.\n     *\n     * @param {Object} config The configuration object.\n     */\n    pattern: RegExp;\n    constructor(config: {\n        clean_text: boolean;\n        handle_chinese_chars: boolean;\n        lowercase: boolean;\n        strip_accents: boolean;\n    }) {\n        super();\n        // Construct a pattern which matches the rust implementation:\n        // https://github.com/huggingface/tokenizers/blob/b4fcc9ce6e4ad5806e82826f816acfdfdc4fcc67/tokenizers/src/pre_tokenizers/bert.rs#L11\n        // Equivalent to removing whitespace and splitting on punctuation (both \\p{P} and other ascii characters)\n        this.pattern = new RegExp(`[^\\\\s${PUNCTUATION_REGEX}]+|[${PUNCTUATION_REGEX}]`, 'gu');\n    }\n    /**\n     * Tokenizes a single text using the BERT pre-tokenization scheme.\n     *\n     * @param {string} text The text to tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        return text.trim().match(this.pattern) || [];\n    }\n}\n\n/**\n * A pre-tokenizer that splits text into Byte-Pair-Encoding (BPE) subwords.\n * @extends PreTokenizer\n */\nclass ByteLevelPreTokenizer extends PreTokenizer {\n    /**\n     * Creates a new instance of the `ByteLevelPreTokenizer` class.\n     * @param {Object} config The configuration object.\n     */\n    config: any;\n    add_prefix_space: boolean;\n    trim_offsets: boolean;\n    use_regex: boolean;\n    pattern: RegExp;\n    byte_encoder: any;\n    text_encoder: any;\n    constructor(config: { add_prefix_space: boolean; trim_offsets: boolean }) {\n        super();\n        this.config = config;\n\n        /**\n         * @type {boolean} Whether to add a leading space to the first word.\n         * This allows to treat the leading word just as any other word.\n         */\n        this.add_prefix_space = this.config.add_prefix_space;\n\n        /**\n         * @type {boolean} Whether the post processing step should trim offsets\n         * to avoid including whitespaces.\n         * @todo Use this in the pretokenization step.\n         */\n        this.trim_offsets = this.config.trim_offsets;\n\n        /**\n         * @type {boolean} Whether to use the standard GPT2 regex for whitespace splitting.\n         * Set it to False if you want to use your own splitting. Defaults to true.\n         */\n        this.use_regex = this.config.use_regex ?? true;\n        this.pattern = /'s|'t|'re|'ve|'m|'ll|'d| ?\\p{L}+| ?\\p{N}+| ?[^\\s\\p{L}\\p{N}]+|\\s+(?!\\S)|\\s+/gu;\n\n        this.byte_encoder = BYTES_TO_UNICODE;\n        this.text_encoder = new TextEncoder();\n    }\n\n    /**\n     * Tokenizes a single piece of text using byte-level tokenization.\n     * @param {string} text The text to tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        // Add a leading space if the option is enabled\n        if (this.add_prefix_space && !text.startsWith(' ')) {\n            text = ' ' + text;\n        }\n\n        // Split on whitespace and punctuation\n        const tokens = this.use_regex ? text.match(this.pattern) || [] : [text];\n\n        // Maps all our bytes to unicode strings, avoiding control tokens of the BPE (spaces in our case)\n        return tokens.map((token) =>\n            Array.from(this.text_encoder.encode(token), (byte) => this.byte_encoder[(byte as any)]).join(''),\n        );\n    }\n}\n\n/**\n * @typedef {'removed'|'isolated'|'mergedWithPrevious'|'mergedWithNext'|'contiguous'} SplitDelimiterBehavior\n */\ntype SplitDelimiterBehavior = 'removed' | 'isolated' | 'mergedWithPrevious' | 'mergedWithNext' | 'contiguous';\n/**\n * Splits text using a given pattern.\n * @extends PreTokenizer\n */\nclass SplitPreTokenizer extends PreTokenizer {\n    /**\n     * @param {Object} config The configuration options for the pre-tokenizer.\n     * @param {Object} config.pattern The pattern used to split the text. Can be a string or a regex object.\n     * @param {string|undefined} config.pattern.String The string to use for splitting. Only defined if the pattern is a string.\n     * @param {string|undefined} config.pattern.Regex The regex to use for splitting. Only defined if the pattern is a regex.\n     * @param {SplitDelimiterBehavior} config.behavior The behavior to use when splitting.\n     * @param {boolean} config.invert Whether to split (invert=false) or match (invert=true) the pattern.\n     */\n    config: any;\n    pattern: any;\n    constructor(config: { pattern: string | RegExp; behavior: SplitDelimiterBehavior; invert: boolean }) {\n        super();\n        this.config = config;\n        // TODO support all behaviours (config.behavior)\n\n        this.pattern = createPattern(this.config.pattern, this.config.invert);\n    }\n\n    /**\n     * Tokenizes text by splitting it using the given pattern.\n     * @param {string} text The text to tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        if (this.pattern === null) {\n            return [];\n        }\n\n        if (this.config.invert) {\n            return text.match(this.pattern) || [];\n        } else if (this.config.behavior?.toLowerCase() === 'removed') {\n            return text.split(this.pattern).filter((x) => x);\n        } else {\n            return regexSplit(text, this.pattern);\n        }\n    }\n}\n\n/**\n * Splits text based on punctuation.\n * @extends PreTokenizer\n */\nclass PunctuationPreTokenizer extends PreTokenizer {\n    /**\n     * @param {Object} config The configuration options for the pre-tokenizer.\n     * @param {SplitDelimiterBehavior} config.behavior The behavior to use when splitting.\n     */\n    config: any;\n    pattern: RegExp;\n    constructor(config: { behavior: SplitDelimiterBehavior }) {\n        super();\n        this.config = config;\n        this.pattern = new RegExp(`[^${PUNCTUATION_REGEX}]+|[${PUNCTUATION_REGEX}]+`, 'gu');\n    }\n\n    /**\n     * Tokenizes text by splitting it using the given pattern.\n     * @param {string} text The text to tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        return text.match(this.pattern) || [];\n    }\n}\n\n/**\n * Splits text based on digits.\n * @extends PreTokenizer\n */\nclass DigitsPreTokenizer extends PreTokenizer {\n    /**\n     * @param {Object} config The configuration options for the pre-tokenizer.\n     * @param {boolean} config.individual_digits Whether to split on individual digits.\n     */\n    config: any;\n    pattern: RegExp;\n    constructor(config: any) {\n        super();\n        this.config = config;\n\n        // Construct a pattern which matches the rust implementation:\n        const digit_pattern = `[^\\\\d]+|\\\\d${this.config.individual_digits ? '' : '+'}`;\n        this.pattern = new RegExp(digit_pattern, 'gu');\n    }\n\n    /**\n     * Tokenizes text by splitting it using the given pattern.\n     * @param {string} text The text to tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        return text.match(this.pattern) || [];\n    }\n}\n\n/**\n * @typedef {Object} PostProcessedOutput\n * @property {string[]} tokens List of token produced by the post-processor.\n * @property {number[]} [token_type_ids] List of token type ids produced by the post-processor.\n */\n\n/**\n * @typedef {Object} EncodingSingle\n * @property {number[]} input_ids List of token ids to be fed to a model.\n * @property {number[]} attention_mask List of token type ids to be fed to a model\n * @property {number[]} [token_type_ids] List of indices specifying which tokens should be attended to by the model\n */\n\n/**\n * @extends Callable\n */\nclass PostProcessor extends Callable {\n    /**\n     * @param {Object} config The configuration for the post-processor.\n     */\n    config: any;\n    constructor(config: any) {\n        if (!config) {\n            throw new Error('config is required');\n        }\n        super();\n        this.config = config;\n    }\n\n    /**\n     * Factory method to create a PostProcessor object from a configuration object.\n     *\n     * @param {Object} config Configuration object representing a PostProcessor.\n     * @returns {PostProcessor} A PostProcessor object created from the given configuration.\n     * @throws {Error} If an unknown PostProcessor type is encountered.\n     */\n    static fromConfig(config: any) {\n        if (config === null) return null;\n        switch (config.type) {\n            case 'TemplateProcessing':\n                return new TemplateProcessing(config);\n            case 'ByteLevel':\n                return new ByteLevelPostProcessor(config);\n            case 'Sequence':\n                return new PostProcessorSequence(config);\n            default:\n                throw new Error(`Unknown PostProcessor type: ${config.type}`);\n        }\n    }\n\n    /**\n     * Method to be implemented in subclass to apply post-processing on the given tokens.\n     *\n     * @param {Array} tokens The input tokens to be post-processed.\n     * @param {...*} args Additional arguments required by the post-processing logic.\n     * @returns {PostProcessedOutput} The post-processed tokens.\n     * @throws {Error} If the method is not implemented in subclass.\n     */\n    post_process(tokens: string[], ...args: any[]) {\n        throw Error('post_process should be implemented in subclass.');\n    }\n\n    /**\n     * Alias for {@link PostProcessor#post_process}.\n     * @param {Array} tokens The text or array of texts to post-process.\n     * @param {...*} args Additional arguments required by the post-processing logic.\n     * @returns {PostProcessedOutput} The post-processed tokens.\n     */\n    _call(tokens: string[], ...args: any[]) {\n        return this.post_process(tokens, ...args);\n    }\n}\n\n\n/**\n * A class representing a post processor used in tokenization.\n * @extends PostProcessor\n */\nclass TemplateProcessing extends PostProcessor {\n    /**\n     * Creates a new instance of `TemplateProcessing`.\n     * @param {Object} config The configuration options for the post processor.\n     * @param {Array} config.single The template for a single sequence of tokens.\n     * @param {Array} config.pair The template for a pair of sequences of tokens.\n     */\n    single: Array<any>;\n    pair: Array<any>;\n    constructor(config: {\n        single: Array<any>;\n        pair: Array<any>;\n    }) {\n        super(config);\n\n        this.single = config.single;\n        this.pair = config.pair;\n    }\n\n    /**\n     * Replaces special tokens in the template with actual tokens.\n     * @param {string[]} tokens The list of tokens for the first sequence.\n     * @param {string[]} [tokens_pair=null] The list of tokens for the second sequence (optional).\n     * @returns {PostProcessedOutput} An object containing the list of tokens with the special tokens replaced with actual tokens.\n     */\n    post_process(tokens: string[], tokens_pair: string[] | null, {\n        add_special_tokens = true,\n    } = {}) {\n        const type = tokens_pair === null ? this.single : this.pair\n\n        let processedTokens: string[] = [];\n        let types: number[] = [];\n        for (const item of type) {\n            if ('SpecialToken' in item) {\n                if (add_special_tokens) {\n                    processedTokens.push(item.SpecialToken.id);\n                    types.push(item.SpecialToken.type_id);\n                }\n            } else if ('Sequence' in item) {\n                if (item.Sequence.id === 'A') {\n                    processedTokens = mergeArrays(processedTokens, tokens);\n                    types = mergeArrays(types, new Array(tokens.length).fill(item.Sequence.type_id));\n\n                } else if (item.Sequence.id === 'B') {\n                    processedTokens = mergeArrays(processedTokens, (tokens_pair as string[]));\n                    types = mergeArrays(types, new Array((tokens_pair as string[]).length).fill(item.Sequence.type_id));\n                }\n            }\n        }\n        return { tokens: processedTokens, token_type_ids: types };\n    }\n}\n\n\n/**\n * A PostProcessor that returns the given tokens as is.\n * @extends PostProcessor\n */\nclass ByteLevelPostProcessor extends PostProcessor {\n    /**\n     * Post process the given tokens.\n     * @param {string[]} tokens The list of tokens for the first sequence.\n     * @param {string[]} [tokens_pair=null] The list of tokens for the second sequence (optional).\n     * @returns {PostProcessedOutput} An object containing the post-processed tokens.\n     */\n    post_process(tokens: string[], tokens_pair = null) {\n        if (tokens_pair) {\n            tokens = mergeArrays(tokens, tokens_pair);\n        }\n        return { tokens };\n    }\n}\n\n/**\n * A post-processor that applies multiple post-processors in sequence.\n */\nclass PostProcessorSequence extends PostProcessor {\n    /**\n     * Creates a new instance of PostProcessorSequence.\n     * @param {Object} config The configuration object.\n     * @param {Object[]} config.processors The list of post-processors to apply.\n     */\n    processors: any;\n    constructor(config: any) {\n        super(config as any);\n\n        this.processors = config.processors.map((x: any) => PostProcessor.fromConfig(x));\n    }\n\n    /**\n     * Post process the given tokens.\n     * @param {string[]} tokens The list of tokens for the first sequence.\n     * @param {string[]} [tokens_pair=null] The list of tokens for the second sequence (optional).\n     * @returns {PostProcessedOutput} An object containing the post-processed tokens.\n     */\n    post_process(tokens: string[], tokens_pair: string[] | null = null, options: any = {}) {\n        let token_type_ids;\n        for (const processor of this.processors) {\n            if (processor instanceof ByteLevelPostProcessor) {\n                // Special case where we need to pass the tokens_pair to the post-processor\n                const output = processor.post_process(tokens);\n                tokens = output.tokens;\n                if (tokens_pair) {\n                    const pair_output = processor.post_process(tokens_pair);\n                    tokens_pair = pair_output.tokens;\n                }\n            } else {\n                const output = processor.post_process(tokens, tokens_pair, options);\n                tokens = output.tokens;\n                token_type_ids = output.token_type_ids;\n            }\n        }\n        return { tokens, token_type_ids };\n    }\n}\n\n/**\n * The base class for token decoders.\n * @extends Callable\n */\nclass Decoder extends Callable {\n    /**\n     * Creates an instance of `Decoder`.\n     *\n     * @param {Object} config The configuration object.\n     */\n    added_tokens: AddedToken[];\n    end_of_word_suffix: string | null;\n    trim_offsets: boolean;\n    config: any;\n    // x: any;\n    constructor(config: any) {\n        super();\n        this.config = config;\n\n        /** @type {AddedToken[]} */\n        this.added_tokens = [];\n        this.end_of_word_suffix = null;\n        this.trim_offsets = config.trim_offsets;\n    }\n\n    /**\n     * Creates a decoder instance based on the provided configuration.\n     *\n     * @param {Object} config The configuration object.\n     * @returns {Decoder} A decoder instance.\n     * @throws {Error} If an unknown decoder type is provided.\n     */\n    static fromConfig(config: any) {\n        if (config === null) return null;\n        switch (config.type) {\n            case 'WordPiece':\n                return new WordPieceDecoder(config);\n            case 'Metaspace':\n                return new MetaspaceDecoder(config);\n            case 'ByteLevel':\n                return new ByteLevelDecoder(config);\n\n            case 'Replace':\n                return new ReplaceDecoder(config);\n            case 'ByteFallback':\n                return new ByteFallback(config);\n            case 'Fuse':\n                return new FuseDecoder(config);\n            case 'Strip':\n                return new StripDecoder(config);\n\n            case 'Sequence':\n                return new DecoderSequence(config);\n\n            case 'CTC':\n                return new CTCDecoder(config);\n            case 'BPEDecoder':\n                return new BPEDecoder(config);\n            default:\n                throw new Error(`Unknown Decoder type: ${config.type}`);\n        }\n    }\n\n    /**\n     * Calls the `decode` method.\n     *\n     * @param {string[]} tokens The list of tokens.\n     * @returns {string} The decoded string.\n     */\n    _call(tokens: string[]) {\n        return this.decode(tokens);\n    }\n\n    /**\n     * Decodes a list of tokens.\n     * @param {string[]} tokens The list of tokens.\n     * @returns {string} The decoded string.\n     */\n    decode(tokens: string[]) {\n        return this.decode_chain(tokens).join('');\n    }\n\n    /**\n     * Apply the decoder to a list of tokens.\n     *\n     * @param {string[]} tokens The list of tokens.\n     * @returns {string[]} The decoded list of tokens.\n     * @throws {Error} If the `decode_chain` method is not implemented in the subclass.\n     */\n    decode_chain(tokens: string[]) {\n        throw Error('`decode_chain` should be implemented in subclass.');\n    }\n}\n\nclass ReplaceDecoder extends Decoder {\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        const pattern = createPattern(this.config.pattern);\n        return pattern === null ? tokens : tokens.map((token) => token.replaceAll(pattern, this.config.content));\n    }\n}\n\nclass ByteFallback extends Decoder {\n    text_decoder: TextDecoder;\n\n    constructor(config: any) {\n        super(config as any);\n\n        this.text_decoder = new TextDecoder();\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        const new_tokens = [];\n        let previous_byte_tokens = [];\n\n        for (const token of tokens) {\n            let bytes = null;\n            if (token.length === 6 && token.startsWith('<0x') && token.endsWith('>')) {\n                const byte = parseInt(token.slice(3, 5), 16);\n                if (!isNaN(byte)) {\n                    bytes = byte;\n                }\n            }\n            if (bytes !== null) {\n                previous_byte_tokens.push(bytes);\n            } else {\n                if (previous_byte_tokens.length > 0) {\n                    const string = this.text_decoder.decode(Uint8Array.from(previous_byte_tokens));\n                    new_tokens.push(string);\n                    previous_byte_tokens = [];\n                }\n                new_tokens.push(token);\n            }\n        }\n        if (previous_byte_tokens.length > 0) {\n            const string = this.text_decoder.decode(Uint8Array.from(previous_byte_tokens));\n            new_tokens.push(string);\n            previous_byte_tokens = [];\n        }\n\n        return new_tokens;\n    }\n}\n\n/**\n * Fuse simply fuses all tokens into one big string.\n * It's usually the last decoding step anyway, but this decoder\n * exists incase some decoders need to happen after that step\n */\nclass FuseDecoder extends Decoder {\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        return [tokens.join('')];\n    }\n}\n\nclass StripDecoder extends Decoder {\n    content: string;\n    start: number;\n    stop: number;\n\n    constructor(config: any) {\n        super(config as any);\n\n        this.content = this.config.content;\n        this.start = this.config.start;\n        this.stop = this.config.stop;\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        return tokens.map((token) => {\n            let start_cut = 0;\n            for (let i = 0; i < this.start; ++i) {\n                if (token[i] === this.content) {\n                    start_cut = i + 1;\n                    continue;\n                } else {\n                    break;\n                }\n            }\n\n            let stop_cut = token.length;\n            for (let i = 0; i < this.stop; ++i) {\n                const index = token.length - i - 1;\n                if (token[index] === this.content) {\n                    stop_cut = index;\n                    continue;\n                } else {\n                    break;\n                }\n            }\n\n            return token.slice(start_cut, stop_cut);\n        });\n    }\n}\n\n/**\n * A decoder that decodes a list of WordPiece tokens into a single string.\n * @extends Decoder\n */\nclass WordPieceDecoder extends Decoder {\n    /**\n     * Creates a new instance of WordPieceDecoder.\n     * @param {Object} config The configuration object.\n     * @param {string} config.prefix The prefix used for WordPiece encoding.\n     * @param {boolean} config.cleanup Whether to cleanup the decoded string.\n     */\n    cleanup: boolean;\n    constructor(config: any) {\n        super(config as any);\n        this.cleanup = config.cleanup;\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        return tokens.map((token, i) => {\n            if (i !== 0) {\n                if (token.startsWith(this.config.prefix)) {\n                    // NOTE: .replace() is intended; only replace first occurrence\n                    token = token.replace(this.config.prefix, '');\n                } else {\n                    token = ' ' + token;\n                }\n            }\n            if (this.cleanup) {\n                token = clean_up_tokenization(token);\n            }\n\n            return token;\n        });\n    }\n}\n\n/**\n * Byte-level decoder for tokenization output. Inherits from the `Decoder` class.\n * @extends Decoder\n */\nclass ByteLevelDecoder extends Decoder {\n    /**\n     * Create a `ByteLevelDecoder` object.\n     * @param {Object} config Configuration object.\n     */\n    byte_decoder: Record<string, any>;\n    text_decoder: TextDecoder;\n    end_of_word_suffix: string | null;\n\n    constructor(config: any) {\n        super(config as any);\n\n        this.byte_decoder = UNICODE_TO_BYTES;\n        this.text_decoder = new TextDecoder('utf-8', {\n            fatal: false,\n            ignoreBOM: true,\n        });\n\n        this.end_of_word_suffix = null;\n    }\n\n    /**\n     * Convert an array of tokens to string by decoding each byte.\n     * @param {string[]} tokens Array of tokens to be decoded.\n     * @returns {string} The decoded string.\n     */\n    convert_tokens_to_string(tokens: string[]) {\n        const text = tokens.join('');\n        const byteArray = new Uint8Array([...text].map((c) => this.byte_decoder[c]));\n        const decoded_text = this.text_decoder.decode(byteArray);\n        return decoded_text;\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        // TODO move to base class (like HF)\n        // tokens === filtered_tokens\n\n        // To avoid mixing byte-level and unicode for byte-level BPT\n        // we need to build string separately for added tokens and byte-level tokens\n        // cf. https://github.com/huggingface/transformers/issues/1133\n        const sub_texts = [];\n        let current_sub_text = [];\n        for (const token of tokens) {\n            // tokens sent here are already filtered, so we don't need to do this\n            // if (skip_special_tokens && this.all_special_ids.includes(token)) {\n            //     continue;\n            // }\n\n            if (this.added_tokens.find((x) => x.content === token) !== undefined) {\n                if (current_sub_text.length > 0) {\n                    sub_texts.push(this.convert_tokens_to_string(current_sub_text));\n                    current_sub_text = [];\n                }\n                sub_texts.push(token);\n            } else {\n                current_sub_text.push(token);\n            }\n        }\n        if (current_sub_text.length > 0) {\n            sub_texts.push(this.convert_tokens_to_string(current_sub_text));\n        }\n\n        // TODO add spaces_between_special_tokens and clean_up_tokenization_spaces options\n\n        return sub_texts;\n    }\n}\n\n/**\n * The CTC (Connectionist Temporal Classification) decoder.\n * See https://github.com/huggingface/tokenizers/blob/bb38f390a61883fc2f29d659af696f428d1cda6b/tokenizers/src/decoders/ctc.rs\n */\nclass CTCDecoder extends Decoder {\n    pad_token: string;\n    word_delimiter_token: string;\n    cleanup: boolean;\n\n    constructor(config: any) {\n        super(config as any);\n\n        this.pad_token = this.config.pad_token;\n        this.word_delimiter_token = this.config.word_delimiter_token;\n        this.cleanup = this.config.cleanup;\n    }\n    /**\n     * Converts a connectionist-temporal-classification (CTC) output tokens into a single string.\n     * @param {string[]} tokens Array of tokens to be decoded.\n     * @returns {string} The decoded string.\n     */\n    convert_tokens_to_string(tokens: string[]) {\n        if (tokens.length === 0) return '';\n\n        // group same tokens into non-repeating tokens in CTC style decoding\n        const grouped_tokens = [tokens[0]];\n        for (let i = 1; i < tokens.length; ++i) {\n            if (tokens[i] !== grouped_tokens.at(-1)) {\n                grouped_tokens.push(tokens[i]);\n            }\n        }\n\n        // filter self.pad_token which is used as CTC-blank token\n        const filtered_tokens = grouped_tokens.filter((token) => token !== this.pad_token);\n\n        let text = filtered_tokens.join('');\n        if (this.cleanup) {\n            // cleanup and replace delimiter token\n            text = clean_up_tokenization(text).replaceAll(this.word_delimiter_token, ' ').trim();\n        }\n        return text;\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        return [this.convert_tokens_to_string(tokens)];\n    }\n}\n\n/**\n * Apply a sequence of decoders.\n * @extends Decoder\n */\nclass DecoderSequence extends Decoder {\n    decoders: Decoder[];\n    /**\n     * Creates a new instance of DecoderSequence.\n     * @param {Object} config The configuration object.\n     * @param {Object[]} config.decoders The list of decoders to apply.\n     */\n    constructor(config: any) {\n        super(config as any);\n        this.decoders = config.decoders.map((x: any) => Decoder.fromConfig(x));\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        // Use reduce to apply each decoder to the tokens\n        return this.decoders.reduce((toks: any, decoder: any) => {\n            return decoder.decode_chain(toks);\n        }, tokens);\n    }\n}\n\nclass BPEDecoder extends Decoder {\n    suffix: string;\n    constructor(config: any) {\n        super(config as any);\n\n        this.suffix = this.config.suffix;\n    }\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        return tokens.map((token, i) => {\n            return token.replaceAll(this.suffix, i === tokens.length - 1 ? '' : ' ');\n        });\n    }\n}\n\n// Custom decoder for VITS\nclass VitsDecoder extends Decoder {\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        let decoded = '';\n        for (let i = 1; i < tokens.length; i += 2) {\n            decoded += tokens[i];\n        }\n        return [decoded];\n    }\n}\n\n/**\n * This PreTokenizer replaces spaces with the given replacement character, adds a prefix space if requested,\n * and returns a list of tokens.\n * @extends PreTokenizer\n */\nclass MetaspacePreTokenizer extends PreTokenizer {\n    /**\n     * @param {Object} config The configuration object for the MetaspacePreTokenizer.\n     * @param {boolean} config.add_prefix_space Whether to add a prefix space to the first token.\n     * @param {string} config.replacement The character to replace spaces with.\n     * @param {string} [config.str_rep=config.replacement] An optional string representation of the replacement character.\n     * @param {'first'|'never'|'always'} [config.prepend_scheme='always'] The metaspace prepending scheme.\n     */\n    addPrefixSpace: boolean;\n    replacement: string;\n    strRep: string;\n    prepend_scheme: string;\n    constructor(config: any) {\n        super();\n\n        this.addPrefixSpace = config.add_prefix_space;\n        this.replacement = config.replacement;\n        this.strRep = config.str_rep || this.replacement;\n        this.prepend_scheme = config.prepend_scheme ?? 'always';\n    }\n\n    /**\n     * This method takes a string, replaces spaces with the replacement character,\n     * adds a prefix space if requested, and returns a new list of tokens.\n     * @param {string} text The text to pre-tokenize.\n     * @param {Object} [options] The options for the pre-tokenization.\n     * @param {number} [options.section_index] The index of the section to pre-tokenize.\n     * @returns {string[]} A new list of pre-tokenized tokens.\n     */\n    pre_tokenize_text(text: string, { section_index = undefined } = {}) {\n        let normalized = text.replaceAll(' ', this.strRep);\n\n        if (\n            // We add a prefix space if:\n            //  (1) The addPrefixSpace option is enabled and the normalized\n            //      token does not already start with the replacement character.\n            this.addPrefixSpace &&\n            !normalized.startsWith(this.replacement) &&\n            // and (2) either:\n            //  (a) prepend_scheme is 'always'\n            //  (b) prepend_scheme is 'first' and this is the first section\n            (this.prepend_scheme === 'always' || (this.prepend_scheme === 'first' && section_index === 0))\n        ) {\n            normalized = this.strRep + normalized;\n        }\n        return [normalized];\n    }\n}\n\n/**\n * MetaspaceDecoder class extends the Decoder class and decodes Metaspace tokenization.\n * @extends Decoder\n */\nclass MetaspaceDecoder extends Decoder {\n    /**\n     * Constructs a new MetaspaceDecoder object.\n     * @param {Object} config The configuration object for the MetaspaceDecoder.\n     * @param {boolean} config.add_prefix_space Whether to add a prefix space to the decoded string.\n     * @param {string} config.replacement The string to replace spaces with.\n     */\n    addPrefixSpace: boolean;\n    replacement: string;\n    constructor(config: any) {\n        super(config as any);\n\n        this.addPrefixSpace = config.add_prefix_space;\n        this.replacement = config.replacement;\n    }\n\n    /** @type {Decoder['decode_chain']} */\n    decode_chain(tokens: string[]) {\n        const result = [];\n        for (let i = 0; i < tokens.length; ++i) {\n            let normalized = tokens[i].replaceAll(this.replacement, ' ');\n            if (this.addPrefixSpace && i == 0 && normalized.startsWith(' ')) {\n                normalized = normalized.substring(1);\n            }\n            result.push(normalized);\n        }\n        return result;\n    }\n}\n\n/**\n * A normalizer that applies a precompiled charsmap.\n * This is useful for applying complex normalizations in C++ and exposing them to JavaScript.\n * @extends Normalizer\n * @param {Object} config The configuration object for the Precompiled normalizer.\n * @param {Object} config.precompiled_charsmap The precompiled charsmap object.\n */\nclass Precompiled extends Normalizer {\n    charsmap: any;\n    /**\n     * Create a new instance of Precompiled normalizer.\n     * @param {Object} config The configuration object.\n     * @param {any} config.precompiled_charsmap Precompiled chars mapping.\n     */\n    constructor(config: any) {\n        super(config as any);\n        this.charsmap = config.precompiled_charsmap;\n    }\n\n    /**\n     * Normalizes the given text by applying the precompiled charsmap.\n     * @param {string} text The text to normalize.\n     * @returns {string} The normalized text.\n     */\n    normalize(text: string) {\n        // As stated in the sentencepiece normalization docs (https://github.com/google/sentencepiece/blob/master/doc/normalization.md#use-pre-defined-normalization-rule),\n        // there are 5 pre-defined normalization rules:\n        //  1. nmt_nfkc: NFKC normalization with some additional normalization around spaces. (default)\n        //  2. nfkc: original NFKC normalization.\n        //  3. nmt_nfkc_cf: nmt_nfkc + Unicode case folding (mostly lower casing)\n        //  4. nfkc_cf: nfkc + Unicode case folding.\n        //  5. identity: no normalization\n        //\n        // For now, we only implement the default (nmt_nfkc).\n        // See https://raw.githubusercontent.com/google/sentencepiece/master/data/nmt_nfkc.tsv for the full list of rules.\n        // TODO: detect when a different `this.charsmap` is used.\n\n        text = text.replace(/[\\u0001-\\u0008\\u000B\\u000E-\\u001F\\u007F\\u008F\\u009F]/gm, ''); // Remove control characters\n        text = text.replace(\n            /[\\u0009\\u000A\\u000C\\u000D\\u00A0\\u1680\\u2000-\\u200F\\u2028\\u2029\\u202F\\u205F\\u2581\\u3000\\uFEFF\\uFFFD]/gm,\n            '\\u0020',\n        ); // Replace certain characters with a space\n\n        if (text.includes('\\uFF5E')) {\n            // To match the sentencepiece implementation 100%, we must handle a very strange edge-case.\n            // For some reason, the \"Fullwidth Tilde\" character (\\uFF5E) should not be converted to the standard Tilde character (\\u007E).\n            // However, NFKC normalization does do this conversion. As a result, we split the string on the Fullwidth Tilde character,\n            // perform NFKC normalization on each substring, and then join them back together with the Fullwidth Tilde character.\n            const parts = text.split('\\uFF5E');\n            text = parts.map((part) => part.normalize('NFKC')).join('\\uFF5E');\n        } else {\n            text = text.normalize('NFKC');\n        }\n\n        return text;\n    }\n}\n\n/**\n * A pre-tokenizer that applies a sequence of pre-tokenizers to the input text.\n * @extends PreTokenizer\n */\nclass PreTokenizerSequence extends PreTokenizer {\n    /**\n     * Creates an instance of PreTokenizerSequence.\n     * @param {Object} config The configuration object for the pre-tokenizer sequence.\n     * @param {Object[]} config.pretokenizers An array of pre-tokenizer configurations.\n     */\n    tokenizers: any[];\n    config: any;\n    constructor(config: any) {\n        super();\n        this.tokenizers = config.pretokenizers.map((x: any) => PreTokenizer.fromConfig(x));\n        this.config = config;\n    }\n\n    /**\n     * Applies each pre-tokenizer in the sequence to the input text in turn.\n     * @param {string} text The text to pre-tokenize.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} The pre-tokenized text.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        // Use reduce to apply each tokenizer to the text\n        return this.tokenizers.reduce(\n            (preTokenizedText: any, tokenizer: any) => {\n                return tokenizer.pre_tokenize(preTokenizedText, options);\n            },\n            [text],\n        );\n    }\n}\n\n/**\n * Splits on word boundaries (using the following regular expression: `\\w+|[^\\w\\s]+`).\n */\nclass WhitespacePreTokenizer extends PreTokenizer {\n    /**\n     * Creates an instance of WhitespacePreTokenizer.\n     * @param {Object} config The configuration object for the pre-tokenizer.\n     */\n    constructor(config: any) {\n        super();\n    }\n    /**\n     * Pre-tokenizes the input text by splitting it on word boundaries.\n     * @param {string} text The text to be pre-tokenized.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens produced by splitting the input text on whitespace.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        return text.match(/\\w+|[^\\w\\s]+/g) || [];\n    }\n}\n\n/**\n * Splits a string of text by whitespace characters into individual tokens.\n * @extends PreTokenizer\n */\nclass WhitespaceSplit extends PreTokenizer {\n    /**\n     * Creates an instance of WhitespaceSplit.\n     * @param {Object} config The configuration object for the pre-tokenizer.\n     */\n    constructor(config: any) {\n        super();\n    }\n    /**\n     * Pre-tokenizes the input text by splitting it on whitespace characters.\n     * @param {string} text The text to be pre-tokenized.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens produced by splitting the input text on whitespace.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        return whitespace_split(text);\n    }\n}\n\n// NOTE: `ReplacePreTokenizer` is custom (to support `BlenderbotSmallTokenizer`)\nclass ReplacePreTokenizer extends PreTokenizer {\n    /**\n     * @param {Object} config The configuration options for the pre-tokenizer.\n     * @param {Object} config.pattern The pattern used to split the text. Can be a string or a regex object.\n     * @param {string} config.content What to replace the pattern with.\n     */\n    pattern: any;\n    content: string;\n    config: {\n        pattern: any;\n        content: string;\n    };\n    constructor(config: any) {\n        super();\n        this.config = config;\n        this.pattern = createPattern(this.config.pattern);\n        this.content = this.config.content;\n    }\n\n    /**\n     * Pre-tokenizes the input text by replacing certain characters.\n     * @param {string} text The text to be pre-tokenized.\n     * @param {Object} [options] Additional options for the pre-tokenization logic.\n     * @returns {string[]} An array of tokens produced by replacing certain characters.\n     */\n    pre_tokenize_text(text: string, options: any) {\n        if (this.pattern === null) {\n            return [text];\n        }\n        return [text.replaceAll(this.pattern, this.config.content)];\n    }\n}\n\nconst SPECIAL_TOKEN_ATTRIBUTES = [\n    'bos_token',\n    'eos_token',\n    'unk_token',\n    'sep_token',\n    'pad_token',\n    'cls_token',\n    'mask_token',\n    // additional_special_tokens (TODO)\n];\n\n/**\n *\n * Helper function for padding values of an object, which are each arrays.\n * NOTE: No additional checks are made here for validity of arguments.\n * @param {Record<string, any[]>} item The input object.\n * @param {number} length The length to pad to.\n * @param {(key: string) => any} value_fn Determine the value to fill the array, based on its key.\n * @param {string} side Which side to pad the array.\n * @private\n */\nfunction padHelper(item: Record<string, any[]>, length: number, value_fn: (key: string) => any, side: string) {\n    for (const key of Object.keys(item)) {\n        const diff = length - item[key].length;\n        const value = value_fn(key);\n\n        const padData = new Array(diff).fill(value);\n        item[key] = side === 'right' ? mergeArrays(item[key], padData) : mergeArrays(padData, item[key]);\n    }\n}\n\n/**\n * Helper function for truncating values of an object, which are each arrays.\n * NOTE: No additional checks are made here for validity of arguments.\n * @param {Record<string, any[]>} item The input object.\n * @param {number} length The length to truncate to.\n * @private\n */\nfunction truncateHelper(item: Record<string, any[]>, length: number) {\n    // Setting .length to a lower value truncates the array in-place:\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length\n    for (const key of Object.keys(item)) {\n        item[key].length = length;\n    }\n}\n\n/**\n * @typedef {Object} Message\n * @property {string} role The role of the message (e.g., \"user\" or \"assistant\" or \"system\").\n * @property {string} content The content of the message.\n */\n\ntype Message = {\n    role: string;\n    content: string;\n};\n\nexport class PreTrainedTokenizer extends Callable {\n    return_token_type_ids = false;\n\n    padding_side = 'right';\n    /**\n     * Create a new PreTrainedTokenizer instance.\n     * @param {Object} tokenizerJSON The JSON of the tokenizer.\n     * @param {Object} tokenizerConfig The config of the tokenizer.\n     */\n    _tokenizer_config: any;\n    pre_tokenizer: any;\n    normalizer: any;\n    model: any;\n    post_processor: any;\n    decoder: any;\n    config: any;\n    special_tokens: string[];\n    added_tokens_regex: RegExp | null;\n    mask_token: string | undefined;\n    mask_token_id: number | undefined;\n    pad_token: string | undefined;\n    pad_token_id: number | undefined;\n    sep_token: string | undefined;\n    sep_token_id: number | undefined;\n    unk_token: string | undefined;\n    unk_token_id: number | undefined;\n    bos_token: string | undefined;\n    bos_token_id: number | undefined;\n    eos_token: string | undefined;\n    eos_token_id: number | undefined;\n    model_max_length: number | undefined;\n    remove_space: boolean;\n    clean_up_tokenization_spaces: boolean;\n    legacy: boolean;\n    chat_template: any;\n    _compiled_template_cache: Map<string, any>;\n    all_special_ids: number[];\n    added_tokens: AddedToken[];\n    additional_special_tokens: string[];\n    do_lowercase_and_remove_accent: boolean;\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super();\n\n        this._tokenizer_config = tokenizerConfig;\n        // Construct parts of the tokenizer from the JSON\n        this.normalizer = Normalizer.fromConfig(tokenizerJSON.normalizer);\n        this.pre_tokenizer = PreTokenizer.fromConfig(tokenizerJSON.pre_tokenizer);\n        this.model = TokenizerModel.fromConfig(tokenizerJSON.model, tokenizerConfig);\n        this.post_processor = PostProcessor.fromConfig(tokenizerJSON.post_processor);\n        this.decoder = Decoder.fromConfig(tokenizerJSON.decoder);\n\n        // Add added_tokens to model\n        this.special_tokens = [];\n        this.all_special_ids = [];\n\n        /** @type {AddedToken[]} */\n        this.added_tokens = [];\n        for (const addedToken of tokenizerJSON.added_tokens) {\n            const token = new AddedToken(addedToken);\n            this.added_tokens.push(token);\n\n            this.model.tokens_to_ids.set(token.content, token.id);\n            this.model.vocab[token.id] = token.content;\n\n            if (token.special) {\n                this.special_tokens.push(token.content);\n                this.all_special_ids.push(token.id);\n            }\n        }\n\n        // Update additional_special_tokens\n        this.additional_special_tokens = tokenizerConfig.additional_special_tokens ?? [];\n        this.special_tokens.push(...this.additional_special_tokens);\n        this.special_tokens = [...new Set(this.special_tokens)]; // Remove duplicates\n\n        if (this.decoder) {\n            // Slight hack, but it prevents code duplication:\n            this.decoder.added_tokens = this.added_tokens;\n\n            // Another slight hack to add `end_of_word_suffix` (if present) to the decoder\n            // This is needed for cases where BPE model and ByteLevel decoder are used\n            // For more information, see https://github.com/huggingface/transformers.js/issues/74\n            // TODO: save this to the decoder when exporting?\n            this.decoder.end_of_word_suffix = this.model.end_of_word_suffix;\n        }\n\n        this.added_tokens_regex =\n            this.added_tokens.length > 0\n                ? new RegExp(\n                    this.added_tokens\n                        .slice()\n                        // Sort by length (desc) to avoid early partial matches\n                        .sort((a: any, b: any) => b.content.length - a.content.length)\n                        .map((x: any) => `${x.lstrip ? '\\\\s*' : ''}(${escapeRegExp(x.content)})${x.rstrip ? '\\\\s*' : ''}`)\n                        .join('|'),\n                )\n                : null;\n\n        // Set mask token if present (otherwise will be undefined, which is fine)\n        this.mask_token = this.getToken('mask_token');\n        this.mask_token_id = this.model.tokens_to_ids.get(this.mask_token);\n\n        this.pad_token = this.getToken('pad_token', 'eos_token');\n        this.pad_token_id = this.model.tokens_to_ids.get(this.pad_token);\n\n        this.sep_token = this.getToken('sep_token');\n        this.sep_token_id = this.model.tokens_to_ids.get(this.sep_token);\n\n        this.unk_token = this.getToken('unk_token');\n        this.unk_token_id = this.model.tokens_to_ids.get(this.unk_token);\n\n        this.bos_token = this.getToken('bos_token');\n        this.bos_token_id = this.model.tokens_to_ids.get(this.bos_token);\n\n        this.eos_token = this.getToken('eos_token');\n        this.eos_token_id = this.model.tokens_to_ids.get(this.eos_token);\n\n        this.model_max_length = tokenizerConfig.model_max_length;\n\n        /** @type {boolean} Whether or not to strip the text when tokenizing (removing excess spaces before and after the string). */\n        this.remove_space = tokenizerConfig.remove_space;\n\n        this.clean_up_tokenization_spaces = tokenizerConfig.clean_up_tokenization_spaces ?? true;\n        this.do_lowercase_and_remove_accent = tokenizerConfig.do_lowercase_and_remove_accent ?? false;\n\n        if (tokenizerConfig.padding_side) {\n            this.padding_side = tokenizerConfig.padding_side;\n        }\n\n        this.legacy = false;\n\n        this.chat_template = tokenizerConfig.chat_template ?? null;\n        if (Array.isArray(this.chat_template)) {\n            // Chat templates are stored as lists of dicts with fixed key names,\n            // we reconstruct that into a single dict while loading them.\n            const chat_template = Object.create(null);\n            for (const { name, template } of this.chat_template) {\n                if (typeof name !== 'string' || typeof template !== 'string') {\n                    throw new Error('Chat template must be a list of objects with \"name\" and \"template\" properties');\n                }\n                chat_template[name] = template;\n            }\n            this.chat_template = chat_template;\n        }\n        this._compiled_template_cache = new Map();\n    }\n\n    /**\n     * Returns the value of the first matching key in the tokenizer config object.\n     * @param {...string} keys One or more keys to search for in the tokenizer config object.\n     * @returns {string|null} The value associated with the first matching key, or null if no match is found.\n     * @throws {Error} If an object is found for a matching key and its __type property is not \"AddedToken\".\n     * @private\n     */\n    getToken(...keys: string[]) {\n        for (const key of keys) {\n            const item = this._tokenizer_config[key];\n\n            if (!item) continue;\n\n            if (typeof item === 'object') {\n                if (item.__type === 'AddedToken') {\n                    return item.content;\n                } else {\n                    throw Error(`Unknown token: ${item}`);\n                }\n            } else {\n                return item;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Loads a pre-trained tokenizer from the given `pretrained_model_name_or_path`.\n     *\n     * @param {string} pretrained_model_name_or_path The path to the pre-trained tokenizer.\n     * @param {PretrainedTokenizerOptions} options Additional options for loading the tokenizer.\n     *\n     * @throws {Error} Throws an error if the tokenizer.json or tokenizer_config.json files are not found in the `pretrained_model_name_or_path`.\n     * @returns {Promise<PreTrainedTokenizer>} A new instance of the `PreTrainedTokenizer` class.\n     */\n    static async from_pretrained(\n        pretrained_model_name_or_path: string,\n        {\n            progress_callback = null,\n            config = null,\n            cache_dir = null,\n            local_files_only = false,\n            revision = 'main',\n            legacy: boolean = false,\n        } = {},\n    ) {\n        const info = await loadTokenizer(pretrained_model_name_or_path, {\n            progress_callback,\n            config,\n            cache_dir,\n            local_files_only,\n            revision,\n            legacy: false,\n        });\n\n        // @ts-ignore\n        return new this(...info);\n    }\n\n    /**\n     * @typedef {number[]|number[][]|Tensor} BatchEncodingItem\n     *\n     * @typedef {Object} BatchEncoding Holds the output of the tokenizer's call function.\n     * @property {BatchEncodingItem} input_ids List of token ids to be fed to a model.\n     * @property {BatchEncodingItem} attention_mask List of indices specifying which tokens should be attended to by the model.\n     * @property {BatchEncodingItem} [token_type_ids] List of token type ids to be fed to a model.\n     */\n\n    /**\n     * Encode/tokenize the given text(s).\n     * @param {string|string[]} text The text to tokenize.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string|string[]} [options.text_pair=null] Optional second sequence to be encoded. If set, must be the same type as text.\n     * @param {boolean|'max_length'} [options.padding=false] Whether to pad the input sequences.\n     * @param {boolean} [options.add_special_tokens=true] Whether or not to add the special tokens associated with the corresponding model.\n     * @param {boolean} [options.truncation=null] Whether to truncate the input sequences.\n     * @param {number} [options.max_length=null] Maximum length of the returned list and optionally padding length.\n     * @param {boolean} [options.return_tensor=true] Whether to return the results as Tensors or arrays.\n     * @param {boolean} [options.return_token_type_ids=null] Whether to return the token type ids.\n     * @returns {BatchEncoding} Object to be passed to the model.\n     */\n    _call(\n        // Required positional arguments\n        text: string | string[],\n\n        // Optional keyword arguments\n        {\n            text_pair = null,\n            add_special_tokens = true,\n            padding = false,\n            truncation = null,\n            max_length = null,\n            return_tensor = true, // Different to HF\n            return_token_type_ids = null,\n        }: {\n            text_pair?: string | string[] | null;\n            add_special_tokens?: boolean;\n            padding?: boolean | 'max_length';\n            truncation?: boolean | null;\n            max_length?: number | null;\n            return_tensor?: boolean;\n            return_token_type_ids?: boolean | null;\n        } = {},\n    ) {\n        const isBatched = Array.isArray(text);\n\n        /** @type {EncodingSingle[]} */\n        let encodedTokens;\n\n        if (isBatched) {\n            if (text.length === 0) {\n                throw Error('text array must be non-empty');\n            }\n\n            if (text_pair !== null) {\n                if (!Array.isArray(text_pair)) {\n                    throw Error('text_pair must also be an array');\n                } else if (text.length !== text_pair.length) {\n                    throw Error('text and text_pair must have the same length');\n                }\n\n                encodedTokens = text.map((t, i) =>\n                    this._encode_plus(t, { text_pair: text_pair[i] as string | null, add_special_tokens, return_token_type_ids }),\n                );\n            } else {\n                encodedTokens = text.map((x: string) => this._encode_plus(x, { add_special_tokens, return_token_type_ids }));\n            }\n        } else {\n            if (text === null || text === undefined) {\n                throw Error('text may not be null or undefined');\n            }\n\n            if (Array.isArray(text_pair)) {\n                throw Error(\n                    'When specifying `text_pair`, since `text` is a string, `text_pair` must also be a string (i.e., not an array).',\n                );\n            }\n\n            // For single input, we just wrap in an array, and then unwrap later.\n            encodedTokens = [this._encode_plus(text, { text_pair, add_special_tokens, return_token_type_ids })];\n        }\n        // At this point, tokens is batched: [batch_size, tokens]\n        // However, array may be jagged. So, we pad to max_length\n\n        if (max_length === null) {\n            if (padding === 'max_length') {\n                (max_length as any) = this.model_max_length;\n            } else {\n                // Calculate max length from sequences\n                (max_length as any) = max(encodedTokens.map((x) => x.input_ids.length))[0];\n            }\n        } else {\n            if (!truncation) {\n                console.warn(\n                    `Truncation was not explicitly activated but \\`max_length\\` is provided a specific value, please use \\`truncation=true\\` to explicitly truncate examples to max length.`,\n                );\n            }\n        }\n\n        // Ensure it is less than model max length\n        max_length = Math.min((max_length as any), this.model_max_length ?? Infinity);\n\n        if (padding || truncation) {\n            // Perform padding and/or truncation\n            for (let i = 0; i < encodedTokens.length; ++i) {\n                if (encodedTokens[i].input_ids.length === max_length) {\n                    continue;\n                } else if (encodedTokens[i].input_ids.length > max_length) {\n                    // possibly truncate\n                    if (truncation) {\n                        truncateHelper((encodedTokens[i] as any), max_length);\n                    }\n                } else {\n                    // t.length < max_length\n                    // possibly pad\n                    if (padding) {\n                        padHelper(\n                            (encodedTokens[i] as any),\n                            max_length,\n                            (key) => (key === 'input_ids' ? this.pad_token_id : 0),\n                            this.padding_side,\n                        );\n                    }\n                }\n            }\n        }\n\n        const result: any = {};\n\n        if (return_tensor) {\n            if (!(padding && truncation)) {\n                // Not, guaranteed that all items have same length, so\n                // we perform additional check\n\n                if (\n                    encodedTokens.some((x: any) => {\n                        for (const key of Object.keys(x)) {\n                            if (x[key].length !== (encodedTokens as any)[0][key]?.length) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    })\n                ) {\n                    throw Error(\n                        'Unable to create tensor, you should probably activate truncation and/or padding ' +\n                        \"with 'padding=true' and 'truncation=true' to have batched tensors with the same length.\",\n                    );\n                }\n            }\n\n            // Now we actually convert to tensor\n            // NOTE: In the same way as the python library, we return a batched tensor, regardless of\n            // whether we have a single input or multiple inputs.\n            const dims = [encodedTokens.length, encodedTokens[0].input_ids.length];\n            for (const key of Object.keys(encodedTokens[0])) {\n                result[key] = new Tensor(\n                    'int64',\n                    BigInt64Array.from((encodedTokens as any).flatMap((x: any) => x[key]).map(BigInt)),\n                    dims,\n                );\n            }\n        } else {\n            for (const key of Object.keys(encodedTokens[0])) {\n                result[key] = encodedTokens.map((x: any) => x[key]);\n            }\n\n            // If not returning a tensor, we match the input type\n            if (!isBatched) {\n                // Input was not batched, so we unwrap\n                for (const key of Object.keys(result)) {\n                    result[key] = result[key][0];\n                }\n            }\n        }\n\n        return /** @type {BatchEncoding} */ result;\n    }\n\n    /**\n     * Encodes a single text using the preprocessor pipeline of the tokenizer.\n     *\n     * @param {string|null} text The text to encode.\n     * @returns {string[]|null} The encoded tokens.\n     */\n    _encode_text(text: string | null): any[] | null {\n        if (text === null) return null;\n\n        // Actual function which does encoding, for a single text\n        // First, we take care of special tokens. Needed to avoid issues arising from\n        // normalization and/or pretokenization (which may not preserve special tokens)\n        const sections = this.added_tokens_regex ? text.split(this.added_tokens_regex).filter((x) => x) : [text];\n\n        const tokens = sections\n            .map((x: string, section_index: number) => {\n                const addedToken = this.added_tokens.find((t: AddedToken) => t.content === x);\n                if (addedToken !== undefined) {\n                    // Ignore added tokens\n                    return x;\n                } else {\n                    if (this.remove_space === true) {\n                        x = x.trim().split(/\\s+/).join(' ');\n                    }\n                    if (this.do_lowercase_and_remove_accent) {\n                        x = lowercase_and_remove_accent(x);\n                    }\n\n                    if (this.normalizer !== null) {\n                        x = this.normalizer(x);\n                    }\n\n                    // If, after normalization, this section is empty (e.g., trimming whitespace),\n                    // we return an empty array\n                    if (x.length === 0) {\n                        return [];\n                    }\n\n                    const sectionTokens =\n                        this.pre_tokenizer !== null\n                            ? this.pre_tokenizer(x, {\n                                section_index,\n                            })\n                            : [x];\n\n                    const tokens = this.model(sectionTokens);\n\n                    return tokens;\n                }\n            })\n            .flat();\n\n        return tokens;\n    }\n\n    /**\n     * Encodes a single text or a pair of texts using the model's tokenizer.\n     *\n     * @param {string} text The text to encode.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.text_pair=null] The optional second text to encode.\n     * @param {boolean} [options.add_special_tokens=true] Whether or not to add the special tokens associated with the corresponding model.\n     * @param {boolean} [options.return_token_type_ids=null] Whether to return token_type_ids.\n     * @returns {EncodingSingle} An object containing the encoded text.\n     * @private\n     */\n    _encode_plus(\n        text: string,\n        {\n            text_pair = null,\n            add_special_tokens = true,\n            return_token_type_ids = null,\n        }: {\n            text_pair?: string | null;\n            add_special_tokens?: boolean;\n            return_token_type_ids?: boolean | null;\n        } = {},\n    ) {\n        const { tokens, token_type_ids } = this._tokenize_helper(text, { pair: text_pair, add_special_tokens });\n\n        const input_ids = this.model.convert_tokens_to_ids(tokens);\n\n        const result: any = {\n            input_ids,\n            attention_mask: new Array(input_ids.length).fill(1),\n        };\n        if ((return_token_type_ids ?? this.return_token_type_ids) && token_type_ids) {\n            result.token_type_ids = token_type_ids;\n        }\n        return result;\n    }\n\n    /**\n     * Internal helper function to tokenize a text, and optionally a pair of texts.\n     * @param {string} text The text to tokenize.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.pair=null] The optional second text to tokenize.\n     * @param {boolean} [options.add_special_tokens=false] Whether or not to add the special tokens associated with the corresponding model.\n     * @returns {{tokens: string[], token_type_ids?: number[]}} An object containing the tokens and optionally the token type IDs.\n     */\n    _tokenize_helper(\n        text: string,\n        {\n            pair = null,\n            add_special_tokens = false,\n        }: {\n            pair?: string | null;\n            add_special_tokens?: boolean;\n        } = {},\n    ) {\n        const tokens = this._encode_text(text);\n        const tokens2 = this._encode_text(pair);\n\n        return this.post_processor\n            ? this.post_processor(tokens, tokens2, { add_special_tokens })\n            : { tokens: mergeArrays(tokens ?? [], tokens2 ?? []) };\n    }\n\n    /**\n     * Converts a string into a sequence of tokens.\n     * @param {string} text The sequence to be encoded.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.pair] A second sequence to be encoded with the first.\n     * @param {boolean} [options.add_special_tokens=false] Whether or not to add the special tokens associated with the corresponding model.\n     * @returns {string[]} The list of tokens.\n     */\n    tokenize(text: string, { pair = null, add_special_tokens = false } = {}) {\n        return this._tokenize_helper(text, { pair, add_special_tokens }).tokens;\n    }\n\n    /**\n     * Encodes a single text or a pair of texts using the model's tokenizer.\n     *\n     * @param {string} text The text to encode.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.text_pair=null] The optional second text to encode.\n     * @param {boolean} [options.add_special_tokens=true] Whether or not to add the special tokens associated with the corresponding model.\n     * @param {boolean} [options.return_token_type_ids=null] Whether to return token_type_ids.\n     * @returns {number[]} An array of token IDs representing the encoded text(s).\n     */\n    encode(text: string, { text_pair = null, add_special_tokens = true, return_token_type_ids = null } = {}) {\n        return this._encode_plus(text, {\n            text_pair,\n            add_special_tokens,\n            return_token_type_ids,\n        }).input_ids;\n    }\n\n    /**\n     * Decode a batch of tokenized sequences.\n     * @param {number[][]|Tensor} batch List/Tensor of tokenized input sequences.\n     * @param {Object} decode_args (Optional) Object with decoding arguments.\n     * @returns {string[]} List of decoded sequences.\n     */\n    batch_decode(batch: number[][] | Tensor, decode_args = {}) {\n        if (batch instanceof Tensor) {\n            batch = batch.tolist();\n        }\n        return batch.map((x) => this.decode(x, decode_args));\n    }\n\n    /**\n     * Decodes a sequence of token IDs back to a string.\n     *\n     * @param {number[]|bigint[]|Tensor} token_ids List/Tensor of token IDs to decode.\n     * @param {Object} [decode_args={}]\n     * @param {boolean} [decode_args.skip_special_tokens=false] If true, special tokens are removed from the output string.\n     * @param {boolean} [decode_args.clean_up_tokenization_spaces=true] If true, spaces before punctuations and abbreviated forms are removed.\n     *\n     * @returns {string} The decoded string.\n     * @throws {Error} If `token_ids` is not a non-empty array of integers.\n     */\n    decode(token_ids: number[] | bigint[] | Tensor, decode_args = {}) {\n        if (token_ids instanceof Tensor) {\n            token_ids = prepareTensorForDecode(token_ids);\n        }\n\n        if (!Array.isArray(token_ids) || token_ids.length === 0 || !isIntegralNumber(token_ids[0])) {\n            throw Error('token_ids must be a non-empty array of integers.');\n        }\n\n        return this.decode_single(token_ids, decode_args);\n    }\n\n    /**\n     * Decode a single list of token ids to a string.\n     * @param {number[]|bigint[]} token_ids List of token ids to decode\n     * @param {Object} decode_args Optional arguments for decoding\n     * @param {boolean} [decode_args.skip_special_tokens=false] Whether to skip special tokens during decoding\n     * @param {boolean} [decode_args.clean_up_tokenization_spaces=null] Whether to clean up tokenization spaces during decoding.\n     * If null, the value is set to `this.decoder.cleanup` if it exists, falling back to `this.clean_up_tokenization_spaces` if it exists, falling back to `true`.\n     * @returns {string} The decoded string\n     */\n    decode_single(\n        token_ids: number[] | bigint[] | Tensor,\n        { skip_special_tokens = false, clean_up_tokenization_spaces = null },\n    ) {\n        let tokens = this.model.convert_ids_to_tokens(token_ids);\n        if (skip_special_tokens) {\n            tokens = tokens.filter((x: string) => !this.special_tokens.includes(x));\n        }\n\n        // If `this.decoder` is null, we just join tokens with a space:\n        // https://github.com/huggingface/tokenizers/blob/8edec536a737cb04494b454805be16c020abb14f/tokenizers/src/tokenizer/mod.rs#L835\n        /** @type {string} */\n        let decoded = this.decoder ? this.decoder(tokens) : tokens.join(' ');\n\n        // Slight hack, but prevents having to pass `skip_special_tokens` to\n        // each call to `decode`, which would lead to code duplication.\n        if (this.decoder && this.decoder.end_of_word_suffix) {\n            decoded = decoded.replaceAll(this.decoder.end_of_word_suffix, ' ');\n            if (skip_special_tokens) {\n                decoded = decoded.trim();\n            }\n        }\n\n        if (clean_up_tokenization_spaces ?? this.clean_up_tokenization_spaces) {\n            decoded = clean_up_tokenization(decoded);\n        }\n\n        return decoded;\n    }\n\n    /**\n     * Retrieve the chat template string used for tokenizing chat messages. This template is used\n     * internally by the `apply_chat_template` method and can also be used externally to retrieve the model's chat\n     * template for better generation tracking.\n     *\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.chat_template=null]\n     * A Jinja template or the name of a template to use for this conversion.\n     * It is usually not necessary to pass anything to this argument,\n     * as the model's template will be used by default.\n     * @param {Object[]} [options.tools=null]\n     * A list of tools (callable functions) that will be accessible to the model. If the template does not\n     * support function calling, this argument will have no effect. Each tool should be passed as a JSON Schema,\n     * giving the name, description and argument types for the tool. See our\n     * [chat templating guide](https://huggingface.co/docs/transformers/main/en/chat_templating#automated-function-conversion-for-tool-use)\n     * for more information.\n     * @returns {string} The chat template string.\n     */\n    get_chat_template({ chat_template = null, tools = null } = {}) {\n        // First, handle the cases when the model has a dict of multiple templates\n        if (this.chat_template && typeof this.chat_template === 'object') {\n            const template_dict = this.chat_template;\n\n            if (chat_template !== null && Object.hasOwn(template_dict, chat_template)) {\n                // The user can pass the name of a template to the chat template argument instead of an entire template\n                chat_template = template_dict[chat_template];\n            } else if (chat_template === null) {\n                if (tools !== null && 'tool_use' in template_dict) {\n                    chat_template = template_dict['tool_use'];\n                } else if ('default' in template_dict) {\n                    chat_template = template_dict['default'];\n                } else {\n                    throw Error(\n                        `This model has multiple chat templates with no default specified! Please either pass a chat ` +\n                        `template or the name of the template you wish to use to the 'chat_template' argument. Available ` +\n                        `template names are ${Object.keys(template_dict).sort()}.`,\n                    );\n                }\n            }\n        } else if (chat_template === null) {\n            // These are the cases when the model has a single template\n            // priority: `chat_template` argument > `tokenizer.chat_template`\n            if (this.chat_template) {\n                chat_template = this.chat_template;\n            } else {\n                throw Error(\n                    'Cannot use apply_chat_template() because tokenizer.chat_template is not set and no template ' +\n                    'argument was passed! For information about writing templates and setting the ' +\n                    'tokenizer.chat_template attribute, please see the documentation at ' +\n                    'https://huggingface.co/docs/transformers/main/en/chat_templating',\n                );\n            }\n        }\n        return chat_template;\n    }\n\n    /**\n     * Converts a list of message objects with `\"role\"` and `\"content\"` keys to a list of token\n     * ids. This method is intended for use with chat models, and will read the tokenizer's chat_template attribute to\n     * determine the format and control tokens to use when converting.\n     *\n     * See [here](https://huggingface.co/docs/transformers/chat_templating) for more information.\n     *\n     * **Example:** Applying a chat template to a conversation.\n     *\n     * ```javascript\n     * import { AutoTokenizer } from \"@huggingface/transformers\";\n     *\n     * const tokenizer = await AutoTokenizer.from_pretrained(\"Xenova/mistral-tokenizer-v1\");\n     *\n     * const chat = [\n     *   { \"role\": \"user\", \"content\": \"Hello, how are you?\" },\n     *   { \"role\": \"assistant\", \"content\": \"I'm doing great. How can I help you today?\" },\n     *   { \"role\": \"user\", \"content\": \"I'd like to show off how chat templating works!\" },\n     * ]\n     *\n     * const text = tokenizer.apply_chat_template(chat, { tokenize: false });\n     * // \"<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]\"\n     *\n     * const input_ids = tokenizer.apply_chat_template(chat, { tokenize: true, return_tensor: false });\n     * // [1, 733, 16289, 28793, 22557, 28725, 910, 460, 368, 28804, 733, 28748, 16289, 28793, 28737, 28742, 28719, 2548, 1598, 28723, 1602, 541, 315, 1316, 368, 3154, 28804, 2, 28705, 733, 16289, 28793, 315, 28742, 28715, 737, 298, 1347, 805, 910, 10706, 5752, 1077, 3791, 28808, 733, 28748, 16289, 28793]\n     * ```\n     *\n     * @param {Message[]} conversation A list of message objects with `\"role\"` and `\"content\"` keys,\n     * representing the chat history so far.\n     * @param {Object} options An optional object containing the following properties:\n     * @param {string} [options.chat_template=null] A Jinja template to use for this conversion. If\n     * this is not passed, the model's chat template will be used instead.\n     * @param {Object[]} [options.tools=null]\n     * A list of tools (callable functions) that will be accessible to the model. If the template does not\n     * support function calling, this argument will have no effect. Each tool should be passed as a JSON Schema,\n     * giving the name, description and argument types for the tool. See our\n     * [chat templating guide](https://huggingface.co/docs/transformers/main/en/chat_templating#automated-function-conversion-for-tool-use)\n     * for more information.\n     * @param {Record<string, string>[]} [options.documents=null]\n     * A list of dicts representing documents that will be accessible to the model if it is performing RAG\n     * (retrieval-augmented generation). If the template does not support RAG, this argument will have no\n     * effect. We recommend that each document should be a dict containing \"title\" and \"text\" keys. Please\n     * see the RAG section of the [chat templating guide](https://huggingface.co/docs/transformers/main/en/chat_templating#arguments-for-RAG)\n     * for examples of passing documents with chat templates.\n     * @param {boolean} [options.add_generation_prompt=false] Whether to end the prompt with the token(s) that indicate\n     * the start of an assistant message. This is useful when you want to generate a response from the model.\n     * Note that this argument will be passed to the chat template, and so it must be supported in the\n     * template for this argument to have any effect.\n     * @param {boolean} [options.tokenize=true] Whether to tokenize the output. If false, the output will be a string.\n     * @param {boolean} [options.padding=false] Whether to pad sequences to the maximum length. Has no effect if tokenize is false.\n     * @param {boolean} [options.truncation=false] Whether to truncate sequences to the maximum length. Has no effect if tokenize is false.\n     * @param {number} [options.max_length=null] Maximum length (in tokens) to use for padding or truncation. Has no effect if tokenize is false.\n     * If not specified, the tokenizer's `max_length` attribute will be used as a default.\n     * @param {boolean} [options.return_tensor=true] Whether to return the output as a Tensor or an Array. Has no effect if tokenize is false.\n     * @param {boolean} [options.return_dict=true] Whether to return a dictionary with named outputs. Has no effect if tokenize is false.\n     * @param {Object} [options.tokenizer_kwargs={}] Additional options to pass to the tokenizer.\n     * @returns {string | Tensor | number[]| number[][]|BatchEncoding} The tokenized output.\n     */\n    apply_chat_template(\n        conversation: Message[],\n        {\n            tools = null,\n            documents = null,\n            chat_template = null,\n            add_generation_prompt = false,\n            tokenize = true,\n            padding = false,\n            truncation = false,\n            max_length = null,\n            return_tensor = true,\n            return_dict = false,\n            tokenizer_kwargs = {},\n            ...kwargs\n        } = {},\n    ) {\n        chat_template = this.get_chat_template({ chat_template, tools });\n\n        if (typeof chat_template !== 'string') {\n            throw Error(`chat_template must be a string, but got ${typeof chat_template}`);\n        }\n\n        // Compilation function uses a cache to avoid recompiling the same template\n        let compiledTemplate = this._compiled_template_cache.get(chat_template);\n        if (compiledTemplate === undefined) {\n            compiledTemplate = new Template(chat_template);\n            this._compiled_template_cache.set(chat_template, compiledTemplate);\n        }\n\n        const special_tokens_map = Object.create(null);\n        for (const key of SPECIAL_TOKEN_ATTRIBUTES) {\n            const value = this.getToken(key);\n            if (value) {\n                special_tokens_map[key] = value;\n            }\n        }\n\n        const rendered = compiledTemplate.render({\n            messages: conversation,\n            add_generation_prompt,\n            tools,\n            documents,\n            ...special_tokens_map,\n            ...kwargs,\n        });\n\n        if (tokenize) {\n            const out = this._call(rendered, {\n                add_special_tokens: false,\n                padding,\n                truncation,\n                max_length,\n                return_tensor,\n                ...tokenizer_kwargs,\n            });\n            return return_dict ? out : (out as { input_ids: any }).input_ids;\n        }\n\n        return rendered;\n    }\n}\n\n/**\n * BertTokenizer is a class used to tokenize text for BERT models.\n * @extends PreTrainedTokenizer\n */\nexport class BertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\n/**\n * Albert tokenizer\n * @extends PreTrainedTokenizer\n */\nexport class AlbertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class MobileBertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class SqueezeBertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class DebertaTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class DebertaV2Tokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class HerbertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class ConvBertTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class RoFormerTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\nexport class DistilBertTokenizer extends PreTrainedTokenizer { }\nexport class CamembertTokenizer extends PreTrainedTokenizer { }\nexport class XLMTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n        console.warn(\n            'WARNING: `XLMTokenizer` is not yet supported by Hugging Face\\'s \"fast\" tokenizers library. Therefore, you may experience slightly inaccurate results.',\n        );\n    }\n}\nexport class ElectraTokenizer extends PreTrainedTokenizer {\n    return_token_type_ids = true;\n}\n\nexport class T5Tokenizer extends PreTrainedTokenizer { }\nexport class GPT2Tokenizer extends PreTrainedTokenizer { }\nexport class BartTokenizer extends PreTrainedTokenizer { }\nexport class MBartTokenizer extends PreTrainedTokenizer {\n    languageRegex: RegExp;\n    language_codes: string[];\n    lang_to_token: (x: string) => string;\n\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        this.languageRegex = /^[a-z]{2}_[A-Z]{2}$/;\n        this.language_codes = this.special_tokens.filter((x) => this.languageRegex.test(x));\n        this.lang_to_token = (x) => x; // Identity function\n    }\n\n    /**\n     * Helper function to build translation inputs for an `MBartTokenizer`.\n     * @param {string|string[]} raw_inputs The text to tokenize.\n     * @param {Object} tokenizer_options Options to be sent to the tokenizer\n     * @param {Object} generate_kwargs Generation options.\n     * @returns {Object} Object to be passed to the model.\n     */\n    _build_translation_inputs(raw_inputs: string | string[], tokenizer_options: any, generate_kwargs: any) {\n        return _build_translation_inputs(this, raw_inputs, tokenizer_options, generate_kwargs);\n    }\n}\nexport class MBart50Tokenizer extends MBartTokenizer { } // NOTE: extends MBartTokenizer\n\nexport class RobertaTokenizer extends PreTrainedTokenizer { }\n\nexport class BloomTokenizer extends PreTrainedTokenizer { }\n\nconst SPIECE_UNDERLINE = '▁';\n\nexport class LlamaTokenizer extends PreTrainedTokenizer {\n    padding_side = 'left';\n\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        this.legacy = tokenizerConfig.legacy ?? true;\n        if (!this.legacy) {\n            // See https://github.com/huggingface/transformers/pull/24565 for more information\n            this.normalizer = null;\n            this.pre_tokenizer = new MetaspacePreTokenizer({\n                replacement: SPIECE_UNDERLINE,\n                add_prefix_space: true,\n                prepend_scheme: 'first',\n            });\n        }\n    }\n\n    /**\n     * Helper function to handle legacy encoding of SPM tokenizers.\n     * Adapted from https://github.com/huggingface/transformers/blob/e6dcf8abd6f65bb4b6dfc1831b20d9ba49ce00e2/src/transformers/models/t5/tokenization_t5.py#L374-L387\n     * @param {string} text The text to encode.\n     * @returns {string[]} The encoded tokens.\n     */\n    _encode_text(text: string | null) {\n        if (text === null) return null;\n\n        if (this.legacy || text.length === 0) {\n            return super._encode_text(text);\n        }\n\n        let tokens = super._encode_text(SPIECE_UNDERLINE + text.replaceAll(SPIECE_UNDERLINE, ' ')) ?? [];\n        if (tokens.length > 1 && tokens[0] === SPIECE_UNDERLINE && this.special_tokens.includes(tokens[1])) {\n            tokens = tokens.slice(1);\n        }\n        return tokens;\n    }\n}\nexport class CodeLlamaTokenizer extends PreTrainedTokenizer { }\n\nexport class XLMRobertaTokenizer extends PreTrainedTokenizer { }\nexport class MPNetTokenizer extends PreTrainedTokenizer { }\n\nexport class FalconTokenizer extends PreTrainedTokenizer { }\n\nexport class GPTNeoXTokenizer extends PreTrainedTokenizer { }\n\nexport class EsmTokenizer extends PreTrainedTokenizer { }\n\nexport class Qwen2Tokenizer extends PreTrainedTokenizer { }\n\nexport class GemmaTokenizer extends PreTrainedTokenizer { }\n\nexport class Grok1Tokenizer extends PreTrainedTokenizer { }\n\n/**\n * Helper function to build translation inputs for an `NllbTokenizer` or `M2M100Tokenizer`.\n * @param {PreTrainedTokenizer} self The tokenizer instance.\n * @param {string|string[]} raw_inputs The text to tokenize.\n * @param {Object} tokenizer_options Options to be sent to the tokenizer\n * @param {Object} generate_kwargs Generation options.\n * @returns {Object} Object to be passed to the model.\n * @private\n */\nfunction _build_translation_inputs(self: any, raw_inputs: any, tokenizer_options: any, generate_kwargs: any) {\n    if (!('language_codes' in self) || !Array.isArray(self.language_codes)) {\n        throw new Error('Tokenizer must have `language_codes` attribute set and it should be an array of language ids.');\n    }\n    if (!('languageRegex' in self) || !(self.languageRegex instanceof RegExp)) {\n        throw new Error('Tokenizer must have `languageRegex` attribute set and it should be a regular expression.');\n    }\n    if (!('lang_to_token' in self) || typeof self.lang_to_token !== 'function') {\n        throw new Error('Tokenizer must have `lang_to_token` attribute set and it should be a function.');\n    }\n    const src_lang_token = generate_kwargs.src_lang;\n    const tgt_lang_token = generate_kwargs.tgt_lang;\n\n    // Check that the target language is valid:\n    if (!self.language_codes.includes(tgt_lang_token)) {\n        throw new Error(\n            `Target language code \"${tgt_lang_token}\" is not valid. Must be one of: {${self.language_codes.join(', ')}}`,\n        );\n    }\n\n    // Allow `src_lang` to be optional. If not set, we'll use the tokenizer's default.\n    if (src_lang_token !== undefined) {\n        // Check that the source language is valid:\n        if (!self.language_codes.includes(src_lang_token)) {\n            throw new Error(\n                `Source language code \"${src_lang_token}\" is not valid. Must be one of: {${self.language_codes.join(', ')}}`,\n            );\n        }\n\n        // In the same way as the Python library, we override the post-processor\n        // to force the source language to be first:\n        for (const item of self.post_processor.config.single) {\n            if ('SpecialToken' in item && self.languageRegex.test(item.SpecialToken.id)) {\n                item.SpecialToken.id = self.lang_to_token(src_lang_token);\n                break;\n            }\n        }\n        // TODO: Do the same for pair?\n    }\n\n    // Override the `forced_bos_token_id` to force the correct language\n    generate_kwargs.forced_bos_token_id = self.model.convert_tokens_to_ids([self.lang_to_token(tgt_lang_token)])[0];\n\n    return self._call(raw_inputs, tokenizer_options);\n}\n\n/**\n * The NllbTokenizer class is used to tokenize text for NLLB (\"No Language Left Behind\") models.\n *\n * No Language Left Behind (NLLB) is a first-of-its-kind, AI breakthrough project\n * that open-sources models capable of delivering high-quality translations directly\n * between any pair of 200+ languages — including low-resource languages like Asturian,\n * Luganda, Urdu and more. It aims to help people communicate with anyone, anywhere,\n * regardless of their language preferences. For more information, check out their\n * [paper](https://arxiv.org/abs/2207.04672).\n *\n * For a list of supported languages (along with their language codes),\n * @see {@link https://github.com/facebookresearch/flores/blob/main/flores200/README.md#languages-in-flores-200}\n */\nexport class NllbTokenizer extends PreTrainedTokenizer {\n    languageRegex: RegExp;\n    language_codes: string[];\n    lang_to_token: (x: string) => string;\n\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        this.languageRegex = /^[a-z]{3}_[A-Z][a-z]{3}$/;\n        this.language_codes = (this as any).special_tokens.filter((x: string) => this.languageRegex.test(x));\n        this.lang_to_token = (x) => x; // Identity function\n    }\n\n    /**\n     * Helper function to build translation inputs for an `NllbTokenizer`.\n     * @param {string|string[]} raw_inputs The text to tokenize.\n     * @param {Object} tokenizer_options Options to be sent to the tokenizer\n     * @param {Object} generate_kwargs Generation options.\n     * @returns {Object} Object to be passed to the model.\n     */\n    _build_translation_inputs(raw_inputs: any, tokenizer_options: any, generate_kwargs: any) {\n        return _build_translation_inputs(this, raw_inputs, tokenizer_options, generate_kwargs);\n    }\n}\n\n/**\n * The M2M100Tokenizer class is used to tokenize text for M2M100 (\"Many-to-Many\") models.\n *\n * M2M100 is a multilingual encoder-decoder (seq-to-seq) model trained for Many-to-Many\n * multilingual translation. It was introduced in this [paper](https://arxiv.org/abs/2010.11125)\n * and first released in [this](https://github.com/pytorch/fairseq/tree/master/examples/m2m_100) repository.\n *\n * For a list of supported languages (along with their language codes),\n * @see {@link https://huggingface.co/facebook/m2m100_418M#languages-covered}\n */\nexport class M2M100Tokenizer extends PreTrainedTokenizer {\n    languageRegex: RegExp;\n    language_codes: string[];\n    lang_to_token: (x: string) => string;\n\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        this.languageRegex = /^__[a-z]{2,3}__$/;\n        this.language_codes = (this as any).special_tokens\n            .filter((x: string) => this.languageRegex.test(x))\n            .map((x: string) => x.slice(2, -2));\n        this.lang_to_token = (x: string) => `__${x}__`;\n    }\n\n    /**\n     * Helper function to build translation inputs for an `M2M100Tokenizer`.\n     * @param {string|string[]} raw_inputs The text to tokenize.\n     * @param {Object} tokenizer_options Options to be sent to the tokenizer\n     * @param {Object} generate_kwargs Generation options.\n     * @returns {Object} Object to be passed to the model.\n     */\n    _build_translation_inputs(raw_inputs: any, tokenizer_options: any, generate_kwargs: any) {\n        return _build_translation_inputs(this, raw_inputs, tokenizer_options, generate_kwargs);\n    }\n}\n\n/**\n * WhisperTokenizer tokenizer\n * @extends PreTrainedTokenizer\n */\nexport class WhisperTokenizer extends PreTrainedTokenizer {\n    get timestamp_begin() {\n        return (this as any).model.convert_tokens_to_ids(['<|notimestamps|>'])[0] + 1;\n    }\n\n    /**\n     * Decodes automatic speech recognition (ASR) sequences.\n     * @param {Array<{tokens: bigint[], token_timestamps?: number[], stride: number[]}>} sequences The sequences to decode.\n     * @param {Object} options The options to use for decoding.\n     * @returns {Array<string|{chunks?: undefined|Array<{language: string|null, timestamp: Array<number|null>, text: string}>}>} The decoded sequences.\n     */\n    _decode_asr(\n        sequences: { tokens: bigint[]; token_timestamps?: number[]; stride: number[] }[],\n        {\n            return_timestamps = null,\n            return_language = false,\n            time_precision = null,\n            force_full_sequences = true,\n        }: any = {},\n    ) {\n        // Set force_full_sequences=false if you want streaming\n        // TODO add support for `return_language`\n\n        // Internal method meant to only be used by asr pipeline.\n        // Handles all the little quirks specific to whisper to handle\n        // the various options not allowed in other seq2seq models\n\n        // =========== Overview ============\n        // - iterate over all outputs\n        // - all tokens within output\n        // - Each token can be\n        //   - language token\n        //   - special token\n        //   - timestamp token\n        //   - text token\n        // - We accumulate the text tokens.\n        // - We split on end timestamps\n        // - Lots of complexity comes from stride and timestamps\n\n        if (time_precision === null) {\n            throw Error('Must specify time_precision');\n        }\n        let last_language: string | null = null;\n\n        const returnWordTimestamps = return_timestamps === 'word';\n\n        function new_chunk() {\n            return { language: last_language, 'timestamp': [null, null], text: '', words: [] };\n        }\n\n        // Welcome to the state machine!\n        const chunks: any = [];\n        let chunk = new_chunk();\n        let time_offset = 0.0;\n        const timestamp_begin = this.timestamp_begin;\n        // Whisper timestamp tokens start from 0.00 and go to timestamp 30.00 in 0.02 increments.\n        // We can calculate the last time stamp token as timestamp_begin plus the number of tokens\n        // tokens from 0.00 to 30.00 which is 1500.\n        const total_timestamp_tokens = 1500; // (30.00 - 0.00) / 0.02\n        const timestamp_end = timestamp_begin + total_timestamp_tokens;\n\n        let previous_tokens: number[] = [];\n        let previous_token_timestamps: number[] = [];\n\n        let skip = false;\n        let right_stride_start = null;\n\n        const all_special_ids = new Set((this as any).all_special_ids);\n\n        for (const output of sequences) {\n            // NOTE: python version has batches, so it uses [0]\n            const token_ids = output.tokens;\n            const token_timestamps = returnWordTimestamps ? output.token_timestamps : null;\n\n            // These keep track of timestamps within strides, which need\n            // to be skipped and resolve all tokens in a single chunk.\n            let last_timestamp = null;\n            let first_timestamp = timestamp_begin;\n\n            if ('stride' in output) {\n                const [chunk_len, stride_left, stride_right] = output.stride;\n\n                // Offset the timings to account for the other `model_outputs`.\n                time_offset -= stride_left;\n                right_stride_start = chunk_len - stride_right;\n\n                // Keeping track of timestamps within strides\n                // We're going to NOT split on those, and delay until we're\n                // out of BOTH stride. Otherwise lots of issues occur and\n                // corner cases\n                if (stride_left) {\n                    first_timestamp = stride_left / time_precision + timestamp_begin;\n                }\n\n                if (stride_right) {\n                    for (let i = token_ids.length - 1; i >= 0; --i) {\n                        const token = Number(token_ids[i]);\n                        if (token >= timestamp_begin) {\n                            // There can be several token in the right stride\n                            // But the last one is ALWAYS going to be skipped\n                            if (last_timestamp !== null && (token - timestamp_begin) * time_precision < right_stride_start) {\n                                break;\n                            }\n                            last_timestamp = token;\n                        }\n                    }\n                }\n            }\n\n            let current_tokens: number[] = [];\n            let current_token_timestamps: any | null = null;\n\n            // - all tokens within output\n            for (let i = 0; i < token_ids.length; ++i) {\n                const token = Number(token_ids[i]);\n                // 4 possible states for each token\n                // - 1/ Language code\n                // - 2/ all other special tokens (which we ignore)\n                // - 3/ Timestamp\n                // - 4/ Regular text\n\n                if (all_special_ids.has(token)) {\n                    const text = this.decode([token]);\n                    const language = WHISPER_LANGUAGE_MAPPING.get(text.slice(2, -2));\n\n                    if (language !== undefined) {\n                        // 1/ Indeed some language\n                        // TODO Handle when language is different from the previous\n                        // one, and we cannot use timestamped tokens to create chunks\n                        if (last_language !== null && language !== last_language && !return_timestamps) {\n                            previous_tokens.push(...current_tokens);\n                            const resolved_tokens = this.findLongestCommonSequence([previous_tokens], null)[0];\n                            const resolved_text = this.decode(resolved_tokens ?? [], {});\n                            chunk.text = resolved_text;\n                            chunks.push(chunk);\n\n                            // Flush all our temporary context\n                            previous_tokens = [];\n                            current_tokens = [];\n                            chunk = new_chunk();\n                        }\n\n                        last_language = chunk.language = language as string;\n                    } else {\n                        // 2/ This is a regular special token, ignoring it\n                    }\n                } else if (token >= timestamp_begin && token <= timestamp_end) {\n                    // 3/ Timestamp token\n                    const time = (token - timestamp_begin) * time_precision + time_offset;\n                    const rounded_time = round(time, 2);\n\n                    if (last_timestamp !== null && token >= last_timestamp) {\n                        // Whisper outputted a timestamp token, but it falls within\n                        // our stride, so we're going to skip it for the time being\n                        // and resolve this later\n                        // Skip is necessary because timestamp tokens always come\n                        // by pair, so we need to skip the next one too (which would mark the start of another chunk).\n                        skip = true;\n                    } else if (skip || (previous_tokens.length > 0 && token < first_timestamp)) {\n                        skip = false;\n                    } else if (chunk.timestamp[0] === null) {\n                        chunk.timestamp[0] = rounded_time as any;\n                    } else {\n                        // This is the end of the timestamp chunk\n                        if (rounded_time === chunk.timestamp[0]) {\n                            // This is a bug in timestamp token output\n                            // where we're taking the duplicate token\n                            // as a stop where it should be a start.\n                            // This is an issue in the underlying model output\n                            // Let's just skip it so it becomes de-factor a start agin\n                        } else {\n                            chunk.timestamp[1] = rounded_time as any;\n\n                            // Handling merges\n                            previous_tokens.push(...current_tokens);\n\n                            if (returnWordTimestamps && current_token_timestamps) {\n                                previous_token_timestamps.push(...current_token_timestamps);\n                            }\n                            const [resolved_tokens, resolved_token_timestamps] = this.findLongestCommonSequence(\n                                [previous_tokens],\n                                [previous_token_timestamps],\n                            );\n\n                            const resolved_text = this.decode(resolved_tokens ?? [], {});\n                            chunk.text = resolved_text;\n\n                            if (returnWordTimestamps) {\n                                chunk.words = this.collateWordTimestamps(resolved_tokens ?? [], [resolved_token_timestamps ?? []], last_language as string);\n                            }\n\n                            chunks.push(chunk);\n\n                            // Flush all our temporary context\n                            previous_tokens = [];\n                            current_tokens = [];\n                            previous_token_timestamps = [];\n                            current_token_timestamps = [];\n                            chunk = new_chunk();\n                        }\n                    }\n                } else {\n                    // 4/ Regular token\n                    // We just append to the list of all tokens so we can handle\n                    // merges later and decode into text.\n                    current_tokens.push(token);\n\n                    if (returnWordTimestamps) {\n                        let start_time: number = round((token_timestamps as any)[i] + time_offset, 2);\n\n                        let end_time: number | null = null;\n                        if (i + 1 < (token_timestamps as any).length) {\n                            end_time = round((token_timestamps as any)[i + 1] + time_offset, 2);\n\n                            // Do not allow punctuation-only tokens to have a duration.\n                            // This prevents long pauses from messing up the timestamps.\n                            const decoded_text = this.decode([token], {});\n                            if (PUNCTUATION_ONLY_REGEX.test(decoded_text)) {\n                                // Add `time_precision` to avoid overlapping timestamps\n                                end_time = round(Math.min(start_time + time_precision, end_time), 2);\n                            }\n                        } else {\n                            // should never happen\n                            end_time = null;\n                        }\n                        current_token_timestamps.push([(start_time), end_time]);\n                    }\n                }\n            }\n\n            if ('stride' in output) {\n                const [chunk_len, stride_left, stride_right] = output.stride;\n                time_offset += chunk_len - stride_right;\n            }\n\n            // Leftover tokens\n            if (current_tokens.length > 0) {\n                previous_tokens.push(...current_tokens);\n                if (returnWordTimestamps && current_token_timestamps) {\n                    previous_token_timestamps.push(...current_token_timestamps);\n                }\n            } else if (previous_tokens.every((p) => (p as any).length === 0)) {\n                // Flushing previous tokens (END)\"\n                chunk = new_chunk();\n                previous_tokens = [];\n                current_tokens = [];\n                previous_token_timestamps = [];\n                current_token_timestamps = [];\n            }\n        }\n\n        if (previous_tokens.length > 0) {\n            if (force_full_sequences && return_timestamps) {\n                // Last token should always be timestamps, so there shouldn't be\n                // leftover\n                throw new Error(\n                    'Whisper did not predict an ending timestamp, which can happen if audio is cut off in the middle of a word. ' +\n                    'Also make sure WhisperTimeStampLogitsProcessor was used during generation.',\n                );\n            }\n\n            // Happens when we don't use timestamps\n            const [resolved_tokens, resolved_token_timestamps] = this.findLongestCommonSequence(\n                [previous_tokens],\n                [previous_token_timestamps],\n            );\n\n            // Flushing previous tokens (FINAL)\n            const resolved_text = this.decode((resolved_tokens as any), {});\n            chunk.text = resolved_text;\n            if (returnWordTimestamps) {\n                chunk.words = this.collateWordTimestamps((resolved_tokens as any), (resolved_token_timestamps as any), last_language as any);\n            }\n            chunks.push(chunk);\n        }\n\n        let optional = Object.create(null);\n\n        // Preparing and cleaning up the pipeline output\n        const full_text = chunks.map(((chunk: any) => chunk.text)).join('');\n        if (return_timestamps || return_language) {\n            for (let i = 0; i < chunks.length; ++i) {\n                const chunk = chunks[i];\n                if (!return_timestamps) {\n                    delete chunk['timestamp'];\n                }\n\n                if (!return_language) {\n                    delete chunk['language'];\n                }\n            }\n            if (returnWordTimestamps) {\n                const new_chunks: any = [];\n                for (const chunk of chunks) {\n                    for (const word of chunk.words) {\n                        new_chunks.push(word);\n                    }\n                }\n                optional = { chunks: new_chunks };\n            } else {\n                optional = { chunks: chunks };\n            }\n        }\n        return [full_text, optional];\n    }\n\n    /**\n     * Finds the longest common sequence among the provided sequences.\n     * @param {number[][]} sequences An array of sequences of token ids to compare.\n     * @returns {number[][]} The longest common sequence found.\n     * @throws {Error} If there is a bug within the function.\n     * @private\n     */\n    findLongestCommonSequence(sequences: number[][], token_timestamp_sequences: number[][] | null = null) {\n        // It would be much harder to do O(n) because of fault tolerance.\n        // We actually have a really good property which is that the total sequence\n        // MUST be those subsequences in order.\n        // If token_timestamp_sequences is provided, will split those sequences in\n        // exactly the same way.\n        let leftSequence = sequences[0];\n        let leftLength = leftSequence.length;\n        let totalSequence = [];\n\n        const use_token_timestamp_sequences =\n            Array.isArray(token_timestamp_sequences) && token_timestamp_sequences.length > 0;\n        let total_token_timestamp_sequence = use_token_timestamp_sequences ? [] : null;\n        let left_token_timestamp_sequence = use_token_timestamp_sequences ? token_timestamp_sequences[0] : null;\n        for (let i = 1; i < sequences.length; ++i) {\n            const rightSequence = sequences[i];\n            let max = 0.0;\n            let maxIndices = [leftLength, leftLength, 0, 0];\n            // Here we're sliding matches\n            // [a, b, c, d]\n            //          [c, d, f]\n            // =        [c] == [d]\n\n            // [a, b, c, d]\n            //       [c, d, f]\n            // =     [c, d] == [c, d]\n\n            // [a, b, c, d]\n            //    [c, d, f]\n\n            // =  [b, c, d] == [c, d, f]\n\n            // [a, b, c, d]\n            // [c, d, f]\n\n            // [a, b, c] == [c, d, f]\n\n            // [a, b, c, d]\n            // [d, f]\n\n            // [a, b] == [d, f]\n\n            // [a, b, c, d]\n            // [f]\n\n            // [a] == [f]\n\n            const rightLength = rightSequence.length;\n            for (let j = 1; j < leftLength + rightLength; ++j) {\n                // Slightly convoluted because we don't want out of bound indices\n                // This will be necessary for a small conflict resolution optimization\n                // later\n                const leftStart = Math.max(0, leftLength - j);\n                const leftStop = Math.min(leftLength, leftLength + rightLength - j);\n                const left = leftSequence.slice(leftStart, leftStop);\n                const rightStart = Math.max(0, j - leftLength);\n                const rightStop = Math.min(rightLength, j);\n                const right = rightSequence.slice(rightStart, rightStop);\n                if (left.length !== right.length) {\n                    throw new Error(\n                        'There is a bug within whisper `decode_asr` function, please report it. Dropping to prevent bad inference.',\n                    );\n                }\n\n                let matches;\n                if (use_token_timestamp_sequences) {\n                    // Get length of longest subsequence of tokens that match\n                    // and have timestamps that are in order\n                    matches = left.filter(\n                        (elem, idx) =>\n                            elem === right[idx] &&\n                            (left_token_timestamp_sequence as any)[leftStart + idx] <= (token_timestamp_sequences as any)[i][rightStart + idx],\n                    ).length;\n                } else {\n                    matches = left.filter((elem, idx) => elem === right[idx]).length;\n                }\n\n                // epsilon to favor long perfect matches\n                const eps = j / 10000.0;\n                const matching = matches / j + eps;\n                if (matches > 1 && matching > max) {\n                    max = matching;\n                    maxIndices = [leftStart, leftStop, rightStart, rightStop];\n                }\n            }\n            const [leftStart, leftStop, rightStart, rightStop] = maxIndices;\n            const leftMid = Math.floor((leftStop + leftStart) / 2);\n            const rightMid = Math.floor((rightStop + rightStart) / 2);\n            totalSequence.push(...leftSequence.slice(0, leftMid));\n            leftSequence = rightSequence.slice(rightMid);\n            leftLength = leftSequence.length;\n\n            if (use_token_timestamp_sequences) {\n                (total_token_timestamp_sequence as number[][]).push(...[left_token_timestamp_sequence?.slice(0, leftMid) ?? []]);\n                left_token_timestamp_sequence = token_timestamp_sequences[i].slice(rightMid);\n            }\n        }\n        totalSequence.push(...leftSequence);\n\n        if (use_token_timestamp_sequences) {\n            // Major change here\n            (total_token_timestamp_sequence as number[][]).push(...[left_token_timestamp_sequence ?? []]);\n            return [totalSequence, total_token_timestamp_sequence];\n        } else {\n            return [totalSequence, []];\n        }\n    }\n\n    /** @private */\n    collateWordTimestamps(tokens: number[], token_timestamps: number[][], language: string): any {\n        const [words, _, token_indices] = this.combineTokensIntoWords(tokens, language);\n\n        const timings = [];\n        for (let i = 0; i < words.length; ++i) {\n            const indices = token_indices[i];\n            timings.push({\n                text: words[i],\n                timestamp: [token_timestamps[(indices as any).at(0)][0], token_timestamps[(indices as any).at(-1)][1]],\n            });\n        }\n        return timings;\n    }\n\n    /**\n     * Groups tokens by word. Returns a tuple containing a list of strings with the words,\n     * and a list of `token_id` sequences with the tokens making up each word.\n     * @param {number[]} tokens\n     * @param {string} [language]\n     * @param {string} prepend_punctionations\n     * @param {string} append_punctuations\n     *\n     * @private\n     */\n    combineTokensIntoWords(\n        tokens: number[],\n        language: string,\n        prepend_punctionations = '\"\\'\"¡¿([{-',\n        append_punctuations = '\"\\'.。,，!！?？:：\"\")]}、',\n    ) {\n        language = language ?? 'english';\n\n        let words, word_tokens, token_indices;\n\n        if (['chinese', 'japanese', 'thai', 'lao', 'myanmar'].includes(language)) {\n            // These languages don't typically use spaces.\n            [words, word_tokens, token_indices] = this.splitTokensOnUnicode(tokens);\n        } else {\n            [words, word_tokens, token_indices] = this.splitTokensOnSpaces(tokens);\n        }\n\n        return this.mergePunctuations(words, word_tokens, token_indices, prepend_punctionations, append_punctuations);\n    }\n\n    /** @type {PreTrainedTokenizer['decode']} */\n    decode(token_ids: number[] | bigint[] | Tensor, decode_args: any = {}) {\n        let text;\n        // @ts-ignore\n        if (decode_args?.decode_with_timestamps) {\n            if (token_ids instanceof Tensor) {\n                token_ids = prepareTensorForDecode(token_ids);\n            }\n            text = this.decodeWithTimestamps(token_ids as number[], decode_args);\n        } else {\n            text = super.decode(token_ids, decode_args);\n        }\n        // TODO: implement offsets\n        // if (decode_args.output_offsets) {\n        //     let offsets = this.computeOffsets\n        // }\n        return text;\n    }\n\n    /**\n     * @param {number[]|bigint[]} token_ids List of token IDs to decode.\n     * @param {Object} decode_args Optional arguments for decoding\n     * @private\n     */\n    decodeWithTimestamps(token_ids: number[] | bigint[], decode_args: any) {\n        const time_precision = decode_args?.time_precision ?? 0.02;\n\n        const timestamp_begin = (Array.from(this.all_special_ids).at(-1) ?? 0) + 1;\n        /**@type {Array} */\n        let outputs = Array<any>();\n        for (let token of token_ids) {\n            token = Number(token);\n            if (token >= timestamp_begin) {\n                const timestamp = ((token - timestamp_begin) * time_precision).toFixed(2);\n                outputs.push(`<|${timestamp}|>`);\n                outputs.push([]);\n            } else {\n                outputs[outputs.length - 1].push(token);\n            }\n        }\n        outputs = outputs.map((s) => (typeof s === 'string' ? s : super.decode(s, decode_args)));\n\n        return outputs.join('');\n    }\n\n    /**\n     * Combine tokens into words by splitting at any position where the tokens are decoded as valid unicode points.\n     * @param {number[]} tokens\n     * @returns {*}\n     * @private\n     */\n    splitTokensOnUnicode(tokens: number[]) {\n        const decoded_full = this.decode(tokens, {\n            // @ts-ignore\n            decode_with_timestamps: true,\n        });\n        const replacement_char = '\\uFFFD';\n\n        const words = [];\n        const word_tokens = [];\n        const token_indices = [];\n        let current_tokens = [];\n        let current_indices = [];\n        let unicode_offset = 0;\n\n        for (let token_idx = 0; token_idx < tokens.length; ++token_idx) {\n            const token = tokens[token_idx];\n\n            current_tokens.push(token);\n            current_indices.push(token_idx);\n\n            const decoded = this.decode(current_tokens, {\n                // @ts-ignore\n                decode_with_timestamps: true,\n            });\n\n            if (\n                !decoded.includes(replacement_char) ||\n                decoded_full[unicode_offset + decoded.indexOf(replacement_char)] === replacement_char\n            ) {\n                words.push(decoded);\n                word_tokens.push(current_tokens);\n                token_indices.push(current_indices);\n                current_tokens = [];\n                current_indices = [];\n                unicode_offset += decoded.length;\n            }\n        }\n\n        return [words, word_tokens, token_indices];\n    }\n\n    /**\n     * Combine tokens into words by splitting at whitespace and punctuation tokens.\n     * @param {number[]} tokens\n     * @private\n     */\n    splitTokensOnSpaces(tokens: number[]) {\n        const [subwords, subword_tokens_list, subword_indices_list] = this.splitTokensOnUnicode(tokens);\n\n        const words = [];\n        const word_tokens = [];\n        const token_indices = [];\n\n        const punctuationRegex = new RegExp(`^[${PUNCTUATION_REGEX}]$`, 'gu');\n\n        for (let i = 0; i < subwords.length; ++i) {\n            const subword = subwords[i];\n            const subword_tokens = subword_tokens_list[i];\n            const subword_indices = subword_indices_list[i];\n\n            // @ts-ignore\n            const special = subword_tokens[0] >= this.model.tokens_to_ids.get('<|endoftext|>');\n            const with_space = subword.startsWith(' ');\n            const trimmed = subword.trim();\n            const punctuation = punctuationRegex.test(trimmed);\n\n            if (special || with_space || punctuation || words.length === 0) {\n                words.push(subword);\n                word_tokens.push(subword_tokens);\n                token_indices.push(subword_indices);\n            } else {\n                const ix = words.length - 1;\n                words[ix] += subword;\n                word_tokens[ix].push(...subword_tokens);\n                token_indices[ix].push(...subword_indices);\n            }\n        }\n\n        return [words, word_tokens, token_indices];\n    }\n\n    /**\n     * Merges punctuation tokens with neighboring words.\n     * @param {string[]} words\n     * @param {number[][]} tokens\n     * @param {number[][]} indices\n     * @param {string} prepended\n     * @param {string} appended\n     * @private\n     */\n    mergePunctuations(words: string[], tokens: number[][], indices: number[][], prepended: string, appended: string) {\n        const newWords = structuredClone(words);\n        const newTokens = structuredClone(tokens);\n        const newIndices = structuredClone(indices);\n\n        // prepend punctuations\n        let i = newWords.length - 2;\n        let j = newWords.length - 1;\n\n        while (i >= 0) {\n            if (newWords[i].startsWith(' ') && prepended.includes(newWords[i].trim())) {\n                newWords[j] = newWords[i] + newWords[j];\n                newTokens[j] = mergeArrays(newTokens[i], newTokens[j]);\n                newIndices[j] = mergeArrays(newIndices[i], newIndices[j]);\n                newWords[i] = '';\n                newTokens[i] = [];\n                newIndices[i] = [];\n            } else {\n                j = i;\n            }\n            --i;\n        }\n\n        // append punctuations\n        i = 0;\n        j = 1;\n        while (j < newWords.length) {\n            if (!newWords[i].endsWith(' ') && appended.includes(newWords[j])) {\n                newWords[i] += newWords[j];\n                newTokens[i] = mergeArrays(newTokens[i], newTokens[j]);\n                newIndices[i] = mergeArrays(newIndices[i], newIndices[j]);\n                newWords[j] = '';\n                newTokens[j] = [];\n                newIndices[j] = [];\n            } else {\n                i = j;\n            }\n            ++j;\n        }\n\n        return [newWords.filter((x) => x), newTokens.filter((x) => x.length > 0), newIndices.filter((x) => x.length > 0)];\n    }\n}\nexport class CodeGenTokenizer extends PreTrainedTokenizer { }\nexport class CLIPTokenizer extends PreTrainedTokenizer { }\nexport class SiglipTokenizer extends PreTrainedTokenizer { }\n\n/**\n * @todo This model is not yet supported by Hugging Face's \"fast\" tokenizers library (https://github.com/huggingface/tokenizers).\n * Therefore, this implementation (which is based on fast tokenizers) may produce slightly inaccurate results.\n */\nexport class MarianTokenizer extends PreTrainedTokenizer {\n    /**\n     * Create a new MarianTokenizer instance.\n     * @param {Object} tokenizerJSON The JSON of the tokenizer.\n     * @param {Object} tokenizerConfig The config of the tokenizer.\n     */\n    supported_language_codes: string[];\n    languageRegex: RegExp;\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        this.languageRegex = /^(>>\\w+<<)\\s*/g;\n\n        this.supported_language_codes = this.model.vocab.filter((x: string) => this.languageRegex.test(x));\n\n        console.warn(\n            'WARNING: `MarianTokenizer` is not yet supported by Hugging Face\\'s \"fast\" tokenizers library. Therefore, you may experience slightly inaccurate results.',\n        );\n    }\n\n    /**\n     * Encodes a single text. Overriding this method is necessary since the language codes\n     * must be removed before encoding with sentencepiece model.\n     * @see https://github.com/huggingface/transformers/blob/12d51db243a00726a548a43cc333390ebae731e3/src/transformers/models/marian/tokenization_marian.py#L204-L213\n     *\n     * @param {string|null} text The text to encode.\n     * @returns {Array} The encoded tokens.\n     */\n    _encode_text(text: string | null): any {\n        if (text === null) return null;\n\n        // Check if text starts with language code:\n        const [matchInfo, ...remainder] = text.trim().split(this.languageRegex);\n\n        if (remainder.length === 0) {\n            // No language code, encode normally\n            return super._encode_text(matchInfo);\n        } else if (remainder.length === 2) {\n            // Text starts with language code, so we do not encode it with sentencepiece.\n            const [language, text] = remainder;\n\n            if (!this.supported_language_codes.includes(language)) {\n                console.warn(\n                    `Unsupported language code \"${language}\" detected, which may lead to unexpected behavior. Should be one of: ${JSON.stringify(this.supported_language_codes)}`,\n                );\n            }\n            return mergeArrays([language], (super._encode_text as any)(text));\n        }\n    }\n}\n\nexport class Wav2Vec2CTCTokenizer extends PreTrainedTokenizer { }\n\nexport class BlenderbotTokenizer extends PreTrainedTokenizer { }\nexport class BlenderbotSmallTokenizer extends PreTrainedTokenizer { }\n\nexport class SpeechT5Tokenizer extends PreTrainedTokenizer { }\n\nexport class NougatTokenizer extends PreTrainedTokenizer { }\n\nexport class VitsTokenizer extends PreTrainedTokenizer {\n    constructor(tokenizerJSON: any, tokenizerConfig: any) {\n        super(tokenizerJSON, tokenizerConfig);\n\n        // Custom decoder function\n        this.decoder = new VitsDecoder({});\n    }\n}\n\nexport class CohereTokenizer extends PreTrainedTokenizer { }\n\nexport class MgpstrTokenizer extends PreTrainedTokenizer { }\n\n/**\n * Helper class which is used to instantiate pretrained tokenizers with the `from_pretrained` function.\n * The chosen tokenizer class is determined by the type specified in the tokenizer config.\n *\n * @example\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/bert-base-uncased');\n */\nexport class AutoTokenizer {\n    static TOKENIZER_CLASS_MAPPING = {\n        T5Tokenizer,\n        DistilBertTokenizer,\n        CamembertTokenizer,\n        DebertaTokenizer,\n        DebertaV2Tokenizer,\n        BertTokenizer,\n        HerbertTokenizer,\n        ConvBertTokenizer,\n        RoFormerTokenizer,\n        XLMTokenizer,\n        ElectraTokenizer,\n        MobileBertTokenizer,\n        SqueezeBertTokenizer,\n        AlbertTokenizer,\n        GPT2Tokenizer,\n        BartTokenizer,\n        MBartTokenizer,\n        MBart50Tokenizer,\n        RobertaTokenizer,\n        WhisperTokenizer,\n        CodeGenTokenizer,\n        CLIPTokenizer,\n        SiglipTokenizer,\n        MarianTokenizer,\n        BloomTokenizer,\n        NllbTokenizer,\n        M2M100Tokenizer,\n        LlamaTokenizer,\n        CodeLlamaTokenizer,\n        XLMRobertaTokenizer,\n        MPNetTokenizer,\n        FalconTokenizer,\n        GPTNeoXTokenizer,\n        EsmTokenizer,\n        Wav2Vec2CTCTokenizer,\n        BlenderbotTokenizer,\n        BlenderbotSmallTokenizer,\n        SpeechT5Tokenizer,\n        NougatTokenizer,\n        VitsTokenizer,\n        Qwen2Tokenizer,\n        GemmaTokenizer,\n        Grok1Tokenizer,\n        CohereTokenizer,\n        MgpstrTokenizer,\n\n        // Base case:\n        PreTrainedTokenizer,\n    };\n\n    /**\n     * Instantiate one of the tokenizer classes of the library from a pretrained model.\n     *\n     * The tokenizer class to instantiate is selected based on the `tokenizer_class` property of the config object\n     * (either passed as an argument or loaded from `pretrained_model_name_or_path` if possible)\n     *\n     * @param {string} pretrained_model_name_or_path The name or path of the pretrained model. Can be either:\n     * - A string, the *model id* of a pretrained tokenizer hosted inside a model repo on huggingface.co.\n     *   Valid model ids can be located at the root-level, like `bert-base-uncased`, or namespaced under a\n     *   user or organization name, like `dbmdz/bert-base-german-cased`.\n     * - A path to a *directory* containing tokenizer files, e.g., `./my_model_directory/`.\n     * @param {PretrainedTokenizerOptions} options Additional options for loading the tokenizer.\n     *\n     * @returns {Promise<PreTrainedTokenizer>} A new instance of the PreTrainedTokenizer class.\n     */\n    static async from_pretrained(\n        pretrained_model_name_or_path: string,\n        {\n            progress_callback = null,\n            config = null,\n            cache_dir = null,\n            local_files_only = false,\n            revision = 'main',\n            legacy = undefined,\n        }: {\n            progress_callback?: null | ProgressCallback;\n            config?: null | PretrainedConfig;\n            cache_dir?: null | string;\n            local_files_only?: boolean;\n            revision?: string;\n            legacy?: boolean;\n        } = {},\n    ) {\n        const [tokenizerJSON, tokenizerConfig] = await loadTokenizer(pretrained_model_name_or_path, {\n            progress_callback,\n            config,\n            cache_dir,\n            local_files_only,\n            revision,\n            legacy,\n        });\n\n        // Some tokenizers are saved with the \"Fast\" suffix, so we remove that if present.\n        const tokenizerName = tokenizerConfig.tokenizer_class?.replace(/Fast$/, '') ?? 'PreTrainedTokenizer';\n\n        let cls = this.TOKENIZER_CLASS_MAPPING[tokenizerName as keyof typeof this.TOKENIZER_CLASS_MAPPING];\n        if (!cls) {\n            console.warn(`Unknown tokenizer class \"${tokenizerName}\", attempting to construct from base class.`);\n            cls = PreTrainedTokenizer;\n        }\n        return new cls(tokenizerJSON, tokenizerConfig);\n    }\n}\n","const WHISPER_LANGUAGES = [\n  ['en', 'english'],\n  ['zh', 'chinese'],\n  ['de', 'german'],\n  ['es', 'spanish'],\n  ['ru', 'russian'],\n  ['ko', 'korean'],\n  ['fr', 'french'],\n  ['ja', 'japanese'],\n  ['pt', 'portuguese'],\n  ['tr', 'turkish'],\n  ['pl', 'polish'],\n  ['ca', 'catalan'],\n  ['nl', 'dutch'],\n  ['ar', 'arabic'],\n  ['sv', 'swedish'],\n  ['it', 'italian'],\n  ['id', 'indonesian'],\n  ['hi', 'hindi'],\n  ['fi', 'finnish'],\n  ['vi', 'vietnamese'],\n  ['he', 'hebrew'],\n  ['uk', 'ukrainian'],\n  ['el', 'greek'],\n  ['ms', 'malay'],\n  ['cs', 'czech'],\n  ['ro', 'romanian'],\n  ['da', 'danish'],\n  ['hu', 'hungarian'],\n  ['ta', 'tamil'],\n  ['no', 'norwegian'],\n  ['th', 'thai'],\n  ['ur', 'urdu'],\n  ['hr', 'croatian'],\n  ['bg', 'bulgarian'],\n  ['lt', 'lithuanian'],\n  ['la', 'latin'],\n  ['mi', 'maori'],\n  ['ml', 'malayalam'],\n  ['cy', 'welsh'],\n  ['sk', 'slovak'],\n  ['te', 'telugu'],\n  ['fa', 'persian'],\n  ['lv', 'latvian'],\n  ['bn', 'bengali'],\n  ['sr', 'serbian'],\n  ['az', 'azerbaijani'],\n  ['sl', 'slovenian'],\n  ['kn', 'kannada'],\n  ['et', 'estonian'],\n  ['mk', 'macedonian'],\n  ['br', 'breton'],\n  ['eu', 'basque'],\n  ['is', 'icelandic'],\n  ['hy', 'armenian'],\n  ['ne', 'nepali'],\n  ['mn', 'mongolian'],\n  ['bs', 'bosnian'],\n  ['kk', 'kazakh'],\n  ['sq', 'albanian'],\n  ['sw', 'swahili'],\n  ['gl', 'galician'],\n  ['mr', 'marathi'],\n  ['pa', 'punjabi'],\n  ['si', 'sinhala'],\n  ['km', 'khmer'],\n  ['sn', 'shona'],\n  ['yo', 'yoruba'],\n  ['so', 'somali'],\n  ['af', 'afrikaans'],\n  ['oc', 'occitan'],\n  ['ka', 'georgian'],\n  ['be', 'belarusian'],\n  ['tg', 'tajik'],\n  ['sd', 'sindhi'],\n  ['gu', 'gujarati'],\n  ['am', 'amharic'],\n  ['yi', 'yiddish'],\n  ['lo', 'lao'],\n  ['uz', 'uzbek'],\n  ['fo', 'faroese'],\n  ['ht', 'haitian creole'],\n  ['ps', 'pashto'],\n  ['tk', 'turkmen'],\n  ['nn', 'nynorsk'],\n  ['mt', 'maltese'],\n  ['sa', 'sanskrit'],\n  ['lb', 'luxembourgish'],\n  ['my', 'myanmar'],\n  ['bo', 'tibetan'],\n  ['tl', 'tagalog'],\n  ['mg', 'malagasy'],\n  ['as', 'assamese'],\n  ['tt', 'tatar'],\n  ['haw', 'hawaiian'],\n  ['ln', 'lingala'],\n  ['ha', 'hausa'],\n  ['ba', 'bashkir'],\n  ['jw', 'javanese'],\n  ['su', 'sundanese'],\n];\n\n// @ts-ignore\nexport const WHISPER_LANGUAGE_MAPPING = new Map(WHISPER_LANGUAGES);\n// @ts-ignore\nexport const WHISPER_TO_LANGUAGE_CODE_MAPPING = new Map([\n  ...WHISPER_LANGUAGES.map(([k, v]) => [v, k]),\n  ...[\n    ['burmese', 'my'],\n    ['valencian', 'ca'],\n    ['flemish', 'nl'],\n    ['haitian', 'ht'],\n    ['letzeburgesch', 'lb'],\n    ['pushto', 'ps'],\n    ['panjabi', 'pa'],\n    ['moldavian', 'ro'],\n    ['moldovan', 'ro'],\n    ['sinhalese', 'si'],\n    ['castilian', 'es'],\n  ],\n]);\n\n/**\n * @param {string} language The language name or code\n * @returns {string} The language code\n */\nexport function whisper_language_to_code(language) {\n  language = language.toLowerCase();\n\n  // Map to code from user-friendly name (e.g., \"english\" -> \"en\")\n  let language_code = WHISPER_TO_LANGUAGE_CODE_MAPPING.get(language);\n\n  if (language_code === undefined) {\n    // User provided something that is not a language name\n\n    if (WHISPER_LANGUAGE_MAPPING.has(language)) {\n      // User provided the language code directly (e.g., \"en\")\n      language_code = language;\n    } else {\n      // User provided something that is not a language code or name\n      const is_language_code = language.length === 2;\n      const langs = is_language_code ? WHISPER_LANGUAGE_MAPPING.keys() : WHISPER_LANGUAGE_MAPPING.values();\n\n      throw new Error(`Language \"${language}\" is not supported. Must be one of: ${JSON.stringify(langs)}`);\n    }\n  }\n  return language_code;\n}\n","/**\n * @file Helper module for using model configs. For more information, see the corresponding\n * [Python documentation](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoConfig).\n *\n * **Example:** Load an `AutoConfig`.\n *\n * ```javascript\n * import { AutoConfig } from '@huggingface/transformers';\n * const config = await AutoConfig.from_pretrained('bert-base-uncased');\n * console.log(config);\n * // PretrainedConfig {\n * //   \"model_type\": \"bert\",\n * //   \"is_encoder_decoder\": false,\n * //   \"architectures\": [\n * //       \"BertForMaskedLM\"\n * //   ],\n * //   \"vocab_size\": 30522\n * //   \"num_attention_heads\": 12,\n * //   \"num_hidden_layers\": 12,\n * //   \"hidden_size\": 768,\n * //   \"max_position_embeddings\": 512,\n * //   ...\n * // }\n * ```\n *\n * @module configs\n */\n\nimport { pick } from './utils/core';\nimport { getModelJSON, PretrainedOptions } from './utils/hub';\nimport { DataType, DeviceType } from './utils/dtypes';\n/**\n * @typedef {import('./utils/hub.js').PretrainedOptions} PretrainedOptions\n */\n\n/**\n * @typedef {import('./utils/core.js').ProgressCallback} ProgressCallback\n */\n\n/**\n * @typedef {import('./utils/core.js').ProgressInfo} ProgressInfo\n */\n\n/**\n * Loads a config from the specified path.\n * @param {string} pretrained_model_name_or_path The path to the config directory.\n * @param {PretrainedOptions} options Additional options for loading the config.\n * @returns {Promise<Object>} A promise that resolves with information about the loaded config.\n */\nasync function loadConfig(pretrained_model_name_or_path: string, options: PretrainedOptions) {\n  return await getModelJSON(pretrained_model_name_or_path, 'config.json', true, options);\n}\n\n/**\n *\n * @param {PretrainedConfig} config\n * @returns {Object} The normalized configuration.\n */\nfunction getNormalizedConfig(config: PretrainedConfig) {\n  const mapping: { [key: string]: string } = {};\n\n  let init_normalized_config = {};\n  switch (config.model_type as unknown as string) {\n    // Sub-configs\n    case 'llava':\n    case 'paligemma':\n    case 'florence2':\n    case 'llava_onevision':\n    case 'idefics3':\n      // @ts-expect-error TS2339\n      init_normalized_config = getNormalizedConfig(config.text_config);\n      break;\n    case 'moondream1':\n      // @ts-expect-error TS2339\n      init_normalized_config = getNormalizedConfig(config.phi_config);\n      break;\n    case 'musicgen':\n      // @ts-expect-error TS2339\n      init_normalized_config = getNormalizedConfig(config.decoder);\n      break;\n    case 'multi_modality':\n      // @ts-expect-error TS2339\n      init_normalized_config = getNormalizedConfig(config.language_config);\n      break;\n\n    // Decoder-only models\n    case 'gpt2':\n    case 'gptj':\n    case 'jais':\n    case 'codegen':\n    case 'gpt_bigcode':\n      mapping['num_heads'] = 'n_head';\n      mapping['num_layers'] = 'n_layer';\n      mapping['hidden_size'] = 'n_embd';\n      break;\n    case 'gpt_neox':\n    case 'stablelm':\n    case 'opt':\n    case 'falcon':\n      mapping['num_heads'] = 'num_attention_heads';\n      mapping['num_layers'] = 'num_hidden_layers';\n      mapping['hidden_size'] = 'hidden_size';\n      break;\n    case 'llama':\n    case 'olmo':\n    case 'olmo2':\n    case 'mobilellm':\n    case 'granite':\n    case 'cohere':\n    case 'mistral':\n    case 'starcoder2':\n    case 'qwen2':\n    case 'qwen2_vl':\n    case 'phi':\n    case 'phi3':\n    case 'phi3_v':\n      mapping['num_heads'] = 'num_key_value_heads';\n      mapping['num_layers'] = 'num_hidden_layers';\n      mapping['hidden_size'] = 'hidden_size';\n      mapping['num_attention_heads'] = 'num_attention_heads';\n      break;\n    case 'gemma':\n    case 'gemma2':\n      mapping['num_heads'] = 'num_key_value_heads';\n      mapping['num_layers'] = 'num_hidden_layers';\n      mapping['dim_kv'] = 'head_dim';\n      break;\n    case 'openelm':\n      mapping['num_heads'] = 'num_kv_heads';\n      mapping['num_layers'] = 'num_transformer_layers';\n      mapping['dim_kv'] = 'head_dim';\n      break;\n    case 'gpt_neo':\n    case 'donut-swin':\n      mapping['num_heads'] = 'num_heads';\n      mapping['num_layers'] = 'num_layers';\n      mapping['hidden_size'] = 'hidden_size';\n      break;\n    case 'bloom':\n      mapping['num_heads'] = 'n_head';\n      mapping['num_layers'] = 'n_layer';\n      mapping['hidden_size'] = 'hidden_size';\n      break;\n    case 'mpt':\n      mapping['num_heads'] = 'n_heads';\n      mapping['num_layers'] = 'n_layers';\n      mapping['hidden_size'] = 'd_model';\n      break;\n    case 'exaone':\n      mapping['num_heads'] = 'num_key_value_heads';\n      mapping['num_layers'] = 'num_layers';\n      mapping['dim_kv'] = 'head_dim';\n      mapping['num_attention_heads'] = 'num_attention_heads';\n      break;\n\n    // Encoder-decoder models\n    case 't5':\n    case 'mt5':\n    case 'longt5':\n      mapping['num_decoder_layers'] = 'num_decoder_layers';\n      mapping['num_decoder_heads'] = 'num_heads';\n      mapping['decoder_dim_kv'] = 'd_kv';\n      mapping['num_encoder_layers'] = 'num_layers';\n      mapping['num_encoder_heads'] = 'num_heads';\n      mapping['encoder_dim_kv'] = 'd_kv';\n      break;\n    case 'bart':\n    case 'mbart':\n    case 'marian':\n    case 'whisper':\n    case 'm2m_100':\n    case 'blenderbot':\n    case 'blenderbot-small':\n    case 'florence2_language':\n      mapping['num_decoder_layers'] = 'decoder_layers';\n      mapping['num_decoder_heads'] = 'decoder_attention_heads';\n      mapping['decoder_hidden_size'] = 'd_model';\n      mapping['num_encoder_layers'] = 'encoder_layers';\n      mapping['num_encoder_heads'] = 'encoder_attention_heads';\n      mapping['encoder_hidden_size'] = 'd_model';\n      break;\n    case 'speecht5':\n      mapping['num_decoder_layers'] = 'decoder_layers';\n      mapping['num_decoder_heads'] = 'decoder_attention_heads';\n      mapping['decoder_hidden_size'] = 'hidden_size';\n      mapping['num_encoder_layers'] = 'encoder_layers';\n      mapping['num_encoder_heads'] = 'encoder_attention_heads';\n      mapping['encoder_hidden_size'] = 'hidden_size';\n      break;\n    case 'trocr':\n      mapping['num_encoder_layers'] = mapping['num_decoder_layers'] = 'decoder_layers';\n      mapping['num_encoder_heads'] = mapping['num_decoder_heads'] = 'decoder_attention_heads';\n      mapping['encoder_hidden_size'] = mapping['decoder_hidden_size'] = 'd_model';\n      break;\n    case 'musicgen_decoder':\n    case 'moonshine':\n      mapping['num_encoder_layers'] = mapping['num_decoder_layers'] = 'num_hidden_layers';\n      mapping['num_encoder_heads'] = mapping['num_decoder_heads'] = 'num_attention_heads';\n      mapping['encoder_hidden_size'] = mapping['decoder_hidden_size'] = 'hidden_size';\n      break;\n\n    case 'vision-encoder-decoder':\n      // @ts-expect-error TS2339\n      const decoderConfig = getNormalizedConfig(config.decoder);\n\n      const add_encoder_pkv = 'num_decoder_layers' in decoderConfig;\n      const result: Record<string, unknown> = pick(config, ['model_type', 'is_encoder_decoder']);\n      if (add_encoder_pkv) {\n        // Decoder is part of an encoder-decoder model\n        result.num_decoder_layers = (decoderConfig as Record<string, unknown>).num_decoder_layers;\n        result.num_decoder_heads = (decoderConfig as Record<string, unknown>).num_decoder_heads;\n        result.decoder_hidden_size = (decoderConfig as Record<string, unknown>).decoder_hidden_size;\n\n        result.num_encoder_layers = (decoderConfig as Record<string, unknown>).num_encoder_layers;\n        result.num_encoder_heads = (decoderConfig as Record<string, unknown>).num_encoder_heads;\n        result.encoder_hidden_size = (decoderConfig as Record<string, unknown>).encoder_hidden_size;\n      } else {\n        // Decoder is a decoder-only model\n        result.num_layers = (decoderConfig as Record<string, unknown>).num_layers;\n        result.num_heads = (decoderConfig as Record<string, unknown>).num_heads;\n        result.hidden_size = (decoderConfig as Record<string, unknown>).hidden_size;\n      }\n      return result;\n  }\n\n  // NOTE: If `num_attention_heads` is not set, it is assumed to be equal to `num_heads`\n  const normalized_config: Record<string, any> = {\n    ...init_normalized_config,\n    ...pick(config, ['model_type', 'multi_query', 'is_encoder_decoder']),\n  };\n  for (const key in mapping) {\n    normalized_config[key] = (config as Record<string, any>)[mapping[key]];\n  }\n  return normalized_config;\n}\n\n/**\n *\n * @param {PretrainedConfig} config\n * @returns {Record<string, number[]>}\n */\nexport function getKeyValueShapes(config: PretrainedConfig, { prefix = 'past_key_values', batch_size = 1 } = {}) {\n  /** @type {Record<string, number[]>} */\n  const decoderFeeds: Record<string, number[]> = {};\n  const normalized_config = config.normalized_config;\n\n  if (\n    normalized_config.is_encoder_decoder &&\n    'num_encoder_heads' in normalized_config &&\n    'num_decoder_heads' in normalized_config\n  ) {\n    const encoder_dim_kv =\n      normalized_config.encoder_dim_kv ?? normalized_config.encoder_hidden_size / normalized_config.num_encoder_heads;\n    const decoder_dim_kv =\n      normalized_config.decoder_dim_kv ?? normalized_config.decoder_hidden_size / normalized_config.num_decoder_heads;\n\n    const encoder_dims = [batch_size, normalized_config.num_encoder_heads, 0, encoder_dim_kv];\n    const decoder_dims = [batch_size, normalized_config.num_decoder_heads, 0, decoder_dim_kv];\n    for (let i = 0; i < normalized_config.num_decoder_layers; ++i) {\n      decoderFeeds[`${prefix}.${i}.encoder.key`] = encoder_dims;\n      decoderFeeds[`${prefix}.${i}.encoder.value`] = encoder_dims;\n      decoderFeeds[`${prefix}.${i}.decoder.key`] = decoder_dims;\n      decoderFeeds[`${prefix}.${i}.decoder.value`] = decoder_dims;\n    }\n  } else {\n    // Decoders\n    const num_heads = normalized_config.num_heads;\n    const num_layers = normalized_config.num_layers;\n    const dim_kv =\n      normalized_config.dim_kv ?? normalized_config.hidden_size / (normalized_config.num_attention_heads ?? num_heads);\n\n    if (normalized_config.model_type === 'falcon') {\n      // NOTE: Custom implementation for Falcon\n      const dims = [batch_size * num_heads, 0, dim_kv];\n      for (let i = 0; i < num_layers; ++i) {\n        decoderFeeds[`${prefix}.${i}.key`] = dims;\n        decoderFeeds[`${prefix}.${i}.value`] = dims;\n      }\n    } else if (normalized_config.multi_query) {\n      // e.g., for `gpt_bigcode`\n      const dims = [batch_size * num_heads, 0, 2 * dim_kv];\n\n      for (let i = 0; i < num_layers; ++i) {\n        decoderFeeds[`${prefix}.${i}.key_value`] = dims;\n      }\n    } else if (normalized_config.model_type === 'bloom') {\n      // NOTE: Custom implementation for Bloom\n\n      const keyDims = [batch_size * num_heads, dim_kv, 0]; // [batch_size x num_heads,64,past_sequence_length]\n      const valueDims = [batch_size * num_heads, 0, dim_kv]; // [batch_size x num_heads,past_sequence_length,64]\n      for (let i = 0; i < num_layers; ++i) {\n        decoderFeeds[`${prefix}.${i}.key`] = keyDims;\n        decoderFeeds[`${prefix}.${i}.value`] = valueDims;\n      }\n    } else if (normalized_config.model_type === 'openelm') {\n      for (let i = 0; i < num_layers; ++i) {\n        const dims = [batch_size, num_heads[i], 0, dim_kv];\n\n        decoderFeeds[`${prefix}.${i}.key`] = dims;\n        decoderFeeds[`${prefix}.${i}.value`] = dims;\n      }\n    } else {\n      // Decoder-only\n      const dims = [batch_size, num_heads, 0, dim_kv];\n      for (let i = 0; i < num_layers; ++i) {\n        decoderFeeds[`${prefix}.${i}.key`] = dims;\n        decoderFeeds[`${prefix}.${i}.value`] = dims;\n      }\n    }\n  }\n\n  return decoderFeeds;\n}\n/**\n * Base class for all configuration classes. For more information, see the corresponding\n * [Python documentation](https://huggingface.co/docs/transformers/main/en/main_classes/configuration#transformers.PretrainedConfig).\n */\nexport class PretrainedConfig {\n  /** @type {string|null} */\n  model_type: string | null = null;\n\n  /** @type {boolean} */\n  is_encoder_decoder = false;\n\n  /** @type {boolean|undefined} */\n  multi_query?: boolean;\n\n  /** @type {number} */\n  max_position_embeddings!: number;\n\n  /** @type {TransformersJSConfig} */\n  transformers_js_config!: TransformersJSConfig;\n\n  /** @type {Record<string, any>} */\n  normalized_config!: Record<string, any>;\n\n  /**\n   * Create a new PreTrainedTokenizer instance.\n   * @param {Record<string, any>} configJSON The JSON of the config.\n   */\n  constructor(configJSON: Record<string, any>) {\n    Object.assign(this, configJSON);\n    this.normalized_config = getNormalizedConfig(this);\n  }\n\n  /**\n   * Loads a pre-trained config from the given `pretrained_model_name_or_path`.\n   *\n   * @param {string} pretrained_model_name_or_path The path to the pre-trained config.\n   * @param {PretrainedOptions} options Additional options for loading the config.\n   * @throws {Error} Throws an error if the config.json is not found in the `pretrained_model_name_or_path`.\n   *\n   * @returns {Promise<PretrainedConfig>} A new instance of the `PretrainedConfig` class.\n   */\n  static async from_pretrained(\n    pretrained_model_name_or_path: string,\n    {\n      progress_callback = null,\n      config = null as any,\n      cache_dir = null,\n      local_files_only = false,\n      revision = 'main',\n    } = {},\n  ) {\n    if (config && !(config instanceof PretrainedConfig)) {\n      config = new PretrainedConfig(config);\n    }\n\n    const data =\n      config ??\n      (await loadConfig(pretrained_model_name_or_path, {\n        progress_callback,\n        config,\n        cache_dir,\n        local_files_only,\n        revision,\n      }));\n    return new this(data);\n  }\n}\n\n/**\n * Helper class which is used to instantiate pretrained configs with the `from_pretrained` function.\n *\n * @example\n * const config = await AutoConfig.from_pretrained('Xenova/bert-base-uncased');\n */\nexport class AutoConfig {\n  /** @type {typeof PretrainedConfig.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any) {\n    return PretrainedConfig.from_pretrained(pretrained_model_name_or_path, options);\n  }\n}\n\n/**\n * Transformers.js-specific configuration, possibly present in config.json under the key `transformers.js_config`.\n * @typedef {Object} TransformersJSConfig\n * @property {import('./utils/tensor.js').DataType|Record<import('./utils/dtypes.js').DataType, import('./utils/tensor.js').DataType>} [kv_cache_dtype] The data type of the key-value cache.\n * @property {Record<string, number>} [free_dimension_overrides] Override the free dimensions of the model.\n * See https://onnxruntime.ai/docs/tutorials/web/env-flags-and-session-options.html#freedimensionoverrides\n * for more information.\n * @property {import('./utils/devices.js').DeviceType} [device] The default device to use for the model.\n * @property {import('./utils/dtypes.js').DataType|Record<string, import('./utils/dtypes.js').DataType>} [dtype] The default data type to use for the model.\n * @property {boolean|Record<string, boolean>} [use_external_data_format=false] Whether to load the model using the external data format (used for models >= 2GB in size).\n */\nexport type TransformersJSConfig = {\n  kv_cache_dtype?: Record<string, DataType> | DataType;\n  free_dimension_overrides?: Record<string, number>;\n  device?: DeviceType;\n  dtype?: DataType | Record<string, DataType>;\n  use_external_data_format?: boolean | Record<string, boolean>;\n};\n","import { isNullishDimension, saveBlob } from './core';\nimport { getFile } from './hub';\nimport { env, apis } from '../env';\nimport { Tensor } from './tensor';\n\n// // Will be empty (or not used) if running in browser or web-worker\n// import sharp from 'sharp';\n\nlet createCanvasFunction: any;\nlet ImageDataClass: any;\nlet loadImageFunction: any;\nconst IS_BROWSER_OR_WEBWORKER = apis.IS_BROWSER_ENV || apis.IS_WEBWORKER_ENV;\nif (IS_BROWSER_OR_WEBWORKER) {\n  // Running in browser or web-worker\n  createCanvasFunction = (width: number, height: number) => {\n    if (!self.OffscreenCanvas) {\n      throw new Error('OffscreenCanvas not supported by this browser.');\n    }\n    return new self.OffscreenCanvas(width, height);\n  };\n  loadImageFunction = self.createImageBitmap;\n  ImageDataClass = self.ImageData;\n} else {\n  throw new Error('Unable to load image processing library.');\n}\n\n// Defined here: https://github.com/python-pillow/Pillow/blob/a405e8406b83f8bfb8916e93971edc7407b8b1ff/src/libImaging/Imaging.h#L262-L268\nconst RESAMPLING_MAPPING = {\n  0: 'nearest',\n  1: 'lanczos',\n  2: 'bilinear',\n  3: 'bicubic',\n  4: 'box',\n  5: 'hamming',\n};\n\n/**\n * Mapping from file extensions to MIME types.\n */\nconst CONTENT_TYPE_MAP = new Map([\n  ['png', 'image/png'],\n  ['jpg', 'image/jpeg'],\n  ['jpeg', 'image/jpeg'],\n  ['gif', 'image/gif'],\n]);\n\nexport class RawImage {\n  data: Uint8ClampedArray | Uint8Array;\n  width: number;\n  height: number;\n  channels: 1 | 2 | 3 | 4;\n\n  /**\n   * Create a new `RawImage` object.\n   * @param {Uint8ClampedArray|Uint8Array} data The pixel data.\n   * @param {number} width The width of the image.\n   * @param {number} height The height of the image.\n   * @param {1|2|3|4} channels The number of channels.\n   */\n  constructor(data: Uint8ClampedArray | Uint8Array, width: number, height: number, channels: 1 | 2 | 3 | 4) {\n    this.data = data;\n    this.width = width;\n    this.height = height;\n    this.channels = channels;\n  }\n\n  /**\n   * Returns the size of the image (width, height).\n   * @returns {[number, number]} The size of the image (width, height).\n   */\n  get size() {\n    return [this.width, this.height];\n  }\n\n  /**\n   * Helper method for reading an image from a variety of input types.\n   * @param {RawImage|string|URL} input\n   * @returns The image object.\n   *\n   * **Example:** Read image from a URL.\n   * ```javascript\n   * let image = await RawImage.read('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg');\n   * // RawImage {\n   * //   \"data\": Uint8ClampedArray [ 25, 25, 25, 19, 19, 19, ... ],\n   * //   \"width\": 800,\n   * //   \"height\": 533,\n   * //   \"channels\": 3\n   * // }\n   * ```\n   */\n  static async read(input: RawImage | string | URL) {\n    if (input instanceof RawImage) {\n      return input;\n    } else if (typeof input === 'string' || input instanceof URL) {\n      return await this.fromURL(input);\n    } else {\n      throw new Error(`Unsupported input type: ${typeof input}`);\n    }\n  }\n\n  /**\n   * Read an image from a canvas.\n   * @param {HTMLCanvasElement|OffscreenCanvas} canvas The canvas to read the image from.\n   * @returns {RawImage} The image object.\n   */\n  static fromCanvas(canvas: HTMLCanvasElement | OffscreenCanvas) {\n    if (!IS_BROWSER_OR_WEBWORKER) {\n      throw new Error('fromCanvas() is only supported in browser environments.');\n    }\n\n    const ctx = canvas.getContext('2d');\n    if (!ctx) {\n      throw new Error('Failed to get 2D context from canvas');\n    }\n    const data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n    return new RawImage(data, canvas.width, canvas.height, 4);\n  }\n\n  /**\n   * Read an image from a URL or file path.\n   * @param {string|URL} url The URL or file path to read the image from.\n   * @returns {Promise<RawImage>} The image object.\n   */\n  static async fromURL(url: string | URL) {\n    const response = await getFile(url);\n    if (response.status !== 200) {\n      throw new Error(`Unable to read image from \"${url}\" (${response.status} ${response.statusText})`);\n    }\n    const blob = await response.blob();\n    return this.fromBlob(blob);\n  }\n\n  /**\n   * Helper method to create a new Image from a blob.\n   * @param {Blob} blob The blob to read the image from.\n   * @returns {Promise<RawImage>} The image object.\n   */\n  static async fromBlob(blob: Blob) {\n      // Running in environment with canvas\n      const img = await loadImageFunction(blob);\n\n      const ctx = createCanvasFunction(img.width, img.height).getContext('2d');\n\n      // Draw image to context\n      ctx.drawImage(img, 0, 0);\n\n      return new this(ctx.getImageData(0, 0, img.width, img.height).data, img.width, img.height, 4);\n  }\n\n  /**\n   * Helper method to create a new Image from a tensor\n   * @param {Tensor} tensor\n   */\n  static fromTensor(tensor: Tensor, channel_format: 'CHW' | 'HWC' = 'CHW') {\n    if (tensor.dims.length !== 3) {\n      throw new Error(`Tensor should have 3 dimensions, but has ${tensor.dims.length} dimensions.`);\n    }\n\n    if (channel_format === 'CHW') {\n      tensor = tensor.transpose(1, 2, 0);\n    } else if (channel_format === 'HWC') {\n      // Do nothing\n    } else {\n      throw new Error(`Unsupported channel format: ${channel_format}`);\n    }\n    if (!(tensor.data instanceof Uint8ClampedArray || tensor.data instanceof Uint8Array)) {\n      throw new Error(`Unsupported tensor type: ${tensor.type}`);\n    }\n    switch (tensor.dims[2]) {\n      case 1:\n      case 2:\n      case 3:\n      case 4:\n        return new RawImage(tensor.data, tensor.dims[1], tensor.dims[0], tensor.dims[2]);\n      default:\n        throw new Error(`Unsupported number of channels: ${tensor.dims[2]}`);\n    }\n  }\n\n  /**\n   * Convert the image to grayscale format.\n   * @returns {RawImage} `this` to support chaining.\n   */\n  grayscale() {\n    if (this.channels === 1) {\n      return this;\n    }\n\n    const newData = new Uint8ClampedArray(this.width * this.height * 1);\n    switch (this.channels) {\n      case 3: // rgb to grayscale\n      case 4: // rgba to grayscale\n        for (let i = 0, offset = 0; i < this.data.length; i += this.channels) {\n          const red = this.data[i];\n          const green = this.data[i + 1];\n          const blue = this.data[i + 2];\n\n          newData[offset++] = Math.round(0.2989 * red + 0.587 * green + 0.114 * blue);\n        }\n        break;\n      default:\n        throw new Error(`Conversion failed due to unsupported number of channels: ${this.channels}`);\n    }\n    return this._update(newData, this.width, this.height, 1);\n  }\n\n  /**\n   * Convert the image to RGB format.\n   * @returns {RawImage} `this` to support chaining.\n   */\n  rgb() {\n    if (this.channels === 3) {\n      return this;\n    }\n\n    const newData = new Uint8ClampedArray(this.width * this.height * 3);\n\n    switch (this.channels) {\n      case 1: // grayscale to rgb\n        for (let i = 0, offset = 0; i < this.data.length; ++i) {\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i];\n        }\n        break;\n      case 4: // rgba to rgb\n        for (let i = 0, offset = 0; i < this.data.length; i += 4) {\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i + 1];\n          newData[offset++] = this.data[i + 2];\n        }\n        break;\n      default:\n        throw new Error(`Conversion failed due to unsupported number of channels: ${this.channels}`);\n    }\n    return this._update(newData, this.width, this.height, 3);\n  }\n\n  /**\n   * Convert the image to RGBA format.\n   * @returns {RawImage} `this` to support chaining.\n   */\n  rgba() {\n    if (this.channels === 4) {\n      return this;\n    }\n\n    const newData = new Uint8ClampedArray(this.width * this.height * 4);\n\n    switch (this.channels) {\n      case 1: // grayscale to rgba\n        for (let i = 0, offset = 0; i < this.data.length; ++i) {\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i];\n          newData[offset++] = 255;\n        }\n        break;\n      case 3: // rgb to rgba\n        for (let i = 0, offset = 0; i < this.data.length; i += 3) {\n          newData[offset++] = this.data[i];\n          newData[offset++] = this.data[i + 1];\n          newData[offset++] = this.data[i + 2];\n          newData[offset++] = 255;\n        }\n        break;\n      default:\n        throw new Error(`Conversion failed due to unsupported number of channels: ${this.channels}`);\n    }\n\n    return this._update(newData, this.width, this.height, 4);\n  }\n\n  /**\n   * Apply an alpha mask to the image. Operates in place.\n   * @param {RawImage} mask The mask to apply. It should have a single channel.\n   * @returns {RawImage} The masked image.\n   * @throws {Error} If the mask is not the same size as the image.\n   * @throws {Error} If the image does not have 4 channels.\n   * @throws {Error} If the mask is not a single channel.\n   */\n  putAlpha(mask: RawImage) {\n    if (mask.width !== this.width || mask.height !== this.height) {\n      throw new Error(`Expected mask size to be ${this.width}x${this.height}, but got ${mask.width}x${mask.height}`);\n    }\n    if (mask.channels !== 1) {\n      throw new Error(`Expected mask to have 1 channel, but got ${mask.channels}`);\n    }\n\n    const this_data = this.data;\n    const mask_data = mask.data;\n    const num_pixels = this.width * this.height;\n    if (this.channels === 3) {\n      // Convert to RGBA and simultaneously apply mask to alpha channel\n      const newData = new Uint8ClampedArray(num_pixels * 4);\n      for (let i = 0, in_offset = 0, out_offset = 0; i < num_pixels; ++i) {\n        newData[out_offset++] = this_data[in_offset++];\n        newData[out_offset++] = this_data[in_offset++];\n        newData[out_offset++] = this_data[in_offset++];\n        newData[out_offset++] = mask_data[i];\n      }\n      return this._update(newData, this.width, this.height, 4);\n    } else if (this.channels === 4) {\n      // Apply mask to alpha channel in place\n      for (let i = 0; i < num_pixels; ++i) {\n        this_data[4 * i + 3] = mask_data[i];\n      }\n      return this;\n    }\n    throw new Error(`Expected image to have 3 or 4 channels, but got ${this.channels}`);\n  }\n\n  /**\n   * Resize the image to the given dimensions. This method uses the canvas API to perform the resizing.\n   * @param {number} width The width of the new image. `null` or `-1` will preserve the aspect ratio.\n   * @param {number} height The height of the new image. `null` or `-1` will preserve the aspect ratio.\n   * @param {Object} options Additional options for resizing.\n   * @param {0|1|2|3|4|5|string} [options.resample] The resampling method to use.\n   * @returns {Promise<RawImage>} `this` to support chaining.\n   */\n  async resize(width: number, height: number, { resample = 2 } = {}) {\n    // Do nothing if the image already has the desired size\n    if (this.width === width && this.height === height) {\n      return this;\n    }\n\n    // Ensure resample method is a string\n    let resampleMethod = RESAMPLING_MAPPING[resample as keyof typeof RESAMPLING_MAPPING] ?? resample;\n\n    // Calculate width / height to maintain aspect ratio, in the event that\n    // the user passed a null value in.\n    // This allows users to pass in something like `resize(320, null)` to\n    // resize to 320 width, but maintain aspect ratio.\n    const nullish_width = isNullishDimension(width);\n    const nullish_height = isNullishDimension(height);\n    if (nullish_width && nullish_height) {\n      return this;\n    } else if (nullish_width) {\n      width = (height / this.height) * this.width;\n    } else if (nullish_height) {\n      height = (width / this.width) * this.height;\n    }\n\n    if (IS_BROWSER_OR_WEBWORKER) {\n      // TODO use `resample` in browser environment\n\n      // Store number of channels before resizing\n      const numChannels = this.channels;\n\n      // Create canvas object for this image\n      const canvas = this.toCanvas();\n\n      // Actually perform resizing using the canvas API\n      const ctx = createCanvasFunction(width, height).getContext('2d');\n\n      // Draw image to context, resizing in the process\n      ctx.drawImage(canvas, 0, 0, width, height);\n\n      // Create image from the resized data\n      const resizedImage = new RawImage(ctx.getImageData(0, 0, width, height).data, width, height, 4);\n\n      // Convert back so that image has the same number of channels as before\n      return resizedImage.convert(numChannels as 1 | 3 | 4);\n    } else {\n      // Create sharp image from raw data, and resize\n      let img = this.toSharp();\n\n      switch (resampleMethod) {\n        case 'box':\n        case 'hamming':\n          if (resampleMethod === 'box' || resampleMethod === 'hamming') {\n            console.warn(`Resampling method ${resampleMethod} is not yet supported. Using bilinear instead.`);\n            resampleMethod = 'bilinear';\n          }\n\n        case 'nearest':\n        case 'bilinear':\n        case 'bicubic':\n          // Perform resizing using affine transform.\n          // This matches how the python Pillow library does it.\n          img = img.affine([width / this.width, 0, 0, height / this.height], {\n            interpolator: resampleMethod as 'nearest' | 'bilinear' | 'bicubic' | 'nohalo' | 'lbb' | 'vsqbs' | undefined,\n          });\n          break;\n\n        case 'lanczos':\n          // https://github.com/python-pillow/Pillow/discussions/5519\n          // https://github.com/lovell/sharp/blob/main/docs/api-resize.md\n          img = img.resize({\n            width,\n            height,\n            fit: 'fill',\n            kernel: 'lanczos3', // PIL Lanczos uses a kernel size of 3\n          });\n          break;\n\n        default:\n          throw new Error(`Resampling method ${resampleMethod} is not supported.`);\n      }\n\n      return await loadImageFunction(img);\n    }\n  }\n\n  async pad([left, right, top, bottom]: [number, number, number, number]) {\n    left = Math.max(left, 0);\n    right = Math.max(right, 0);\n    top = Math.max(top, 0);\n    bottom = Math.max(bottom, 0);\n\n    if (left === 0 && right === 0 && top === 0 && bottom === 0) {\n      // No padding needed\n      return this;\n    }\n\n    if (IS_BROWSER_OR_WEBWORKER) {\n      // Store number of channels before padding\n      const numChannels = this.channels;\n\n      // Create canvas object for this image\n      const canvas = this.toCanvas();\n\n      const newWidth = this.width + left + right;\n      const newHeight = this.height + top + bottom;\n\n      // Create a new canvas of the desired size.\n      const ctx = createCanvasFunction(newWidth, newHeight).getContext('2d');\n\n      // Draw image to context, padding in the process\n      ctx.drawImage(canvas, 0, 0, this.width, this.height, left, top, this.width, this.height);\n\n      // Create image from the padded data\n      const paddedImage = new RawImage(ctx.getImageData(0, 0, newWidth, newHeight).data, newWidth, newHeight, 4);\n\n      // Convert back so that image has the same number of channels as before\n      return paddedImage.convert(numChannels as 1 | 3 | 4);\n    } \n  }\n\n  async crop([x_min, y_min, x_max, y_max]: [number, number, number, number]) {\n    // Ensure crop bounds are within the image\n    x_min = Math.max(x_min, 0);\n    y_min = Math.max(y_min, 0);\n    x_max = Math.min(x_max, this.width - 1);\n    y_max = Math.min(y_max, this.height - 1);\n\n    // Do nothing if the crop is the entire image\n    if (x_min === 0 && y_min === 0 && x_max === this.width - 1 && y_max === this.height - 1) {\n      return this;\n    }\n\n    const crop_width = x_max - x_min + 1;\n    const crop_height = y_max - y_min + 1;\n\n    if (IS_BROWSER_OR_WEBWORKER) {\n      // Store number of channels before resizing\n      const numChannels = this.channels;\n\n      // Create canvas object for this image\n      const canvas = this.toCanvas();\n\n      // Create a new canvas of the desired size. This is needed since if the\n      // image is too small, we need to pad it with black pixels.\n      const ctx = createCanvasFunction(crop_width, crop_height).getContext('2d');\n\n      // Draw image to context, cropping in the process\n      ctx.drawImage(canvas, x_min, y_min, crop_width, crop_height, 0, 0, crop_width, crop_height);\n\n      // Create image from the resized data\n      const resizedImage = new RawImage(\n        ctx.getImageData(0, 0, crop_width, crop_height).data,\n        crop_width,\n        crop_height,\n        4,\n      );\n\n      // Convert back so that image has the same number of channels as before\n      return resizedImage.convert(numChannels as 1 | 3 | 4);\n    }\n  }\n\n  async center_crop(crop_width: number, crop_height: number) {\n    // If the image is already the desired size, return it\n    if (this.width === crop_width && this.height === crop_height) {\n      return this;\n    }\n\n    // Determine bounds of the image in the new canvas\n    const width_offset = (this.width - crop_width) / 2;\n    const height_offset = (this.height - crop_height) / 2;\n\n    if (IS_BROWSER_OR_WEBWORKER) {\n      // Store number of channels before resizing\n      const numChannels = this.channels;\n\n      // Create canvas object for this image\n      const canvas = this.toCanvas();\n\n      // Create a new canvas of the desired size. This is needed since if the\n      // image is too small, we need to pad it with black pixels.\n      const ctx = createCanvasFunction(crop_width, crop_height).getContext('2d');\n\n      let sourceX = 0;\n      let sourceY = 0;\n      let destX = 0;\n      let destY = 0;\n\n      if (width_offset >= 0) {\n        sourceX = width_offset;\n      } else {\n        destX = -width_offset;\n      }\n\n      if (height_offset >= 0) {\n        sourceY = height_offset;\n      } else {\n        destY = -height_offset;\n      }\n\n      // Draw image to context, cropping in the process\n      ctx.drawImage(canvas, sourceX, sourceY, crop_width, crop_height, destX, destY, crop_width, crop_height);\n\n      // Create image from the resized data\n      const resizedImage = new RawImage(\n        ctx.getImageData(0, 0, crop_width, crop_height).data,\n        crop_width,\n        crop_height,\n        4,\n      );\n\n      // Convert back so that image has the same number of channels as before\n      return resizedImage.convert(numChannels as 1 | 3 | 4);\n    }\n  }\n\n  async toBlob(type = 'image/png', quality = 1) {\n    if (!IS_BROWSER_OR_WEBWORKER) {\n      throw new Error('toBlob() is only supported in browser environments.');\n    }\n\n    const canvas = this.toCanvas();\n    return await canvas.convertToBlob({ type, quality });\n  }\n\n  toTensor(channel_format = 'CHW') {\n    let tensor = new Tensor('uint8', new Uint8Array(this.data), [this.height, this.width, this.channels]);\n\n    if (channel_format === 'HWC') {\n      // Do nothing\n    } else if (channel_format === 'CHW') {\n      // hwc -> chw\n      tensor = tensor.permute(2, 0, 1);\n    } else {\n      throw new Error(`Unsupported channel format: ${channel_format}`);\n    }\n    return tensor;\n  }\n\n  toCanvas() {\n    if (!IS_BROWSER_OR_WEBWORKER) {\n      throw new Error('toCanvas() is only supported in browser environments.');\n    }\n\n    // Clone, and convert data to RGBA before drawing to canvas.\n    // This is because the canvas API only supports RGBA\n    const cloned = this.clone().rgba();\n\n    // Create canvas object for the cloned image\n    const clonedCanvas = createCanvasFunction(cloned.width, cloned.height);\n\n    // Draw image to context\n    const data = new ImageDataClass(cloned.data, cloned.width, cloned.height);\n    clonedCanvas.getContext('2d').putImageData(data, 0, 0);\n\n    return clonedCanvas;\n  }\n\n  /**\n   * Split this image into individual bands. This method returns an array of individual image bands from an image.\n   * For example, splitting an \"RGB\" image creates three new images each containing a copy of one of the original bands (red, green, blue).\n   *\n   * Inspired by PIL's `Image.split()` [function](https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.split).\n   * @returns {RawImage[]} An array containing bands.\n   */\n  split() {\n    const { data, width, height, channels } = this;\n\n    /** @type {typeof Uint8Array | typeof Uint8ClampedArray} */\n    const data_type = /** @type {any} */ data.constructor;\n    const per_channel_length = data.length / channels;\n\n    // Pre-allocate buffers for each channel\n    const split_data = Array.from(\n      { length: channels },\n      () => new (data_type as new (length: number) => Uint8Array | Uint8ClampedArray)(per_channel_length),\n    );\n\n    // Write pixel data\n    for (let i = 0; i < per_channel_length; ++i) {\n      const data_offset = channels * i;\n      for (let j = 0; j < channels; ++j) {\n        split_data[j][i] = data[data_offset + j];\n      }\n    }\n    return split_data.map((data) => new RawImage(data, width, height, 1));\n  }\n\n  /**\n   * Helper method to update the image data.\n   * @param {Uint8ClampedArray} data The new image data.\n   * @param {number} width The new width of the image.\n   * @param {number} height The new height of the image.\n   * @param {1|2|3|4|null} [channels] The new number of channels of the image.\n   * @private\n   */\n  _update(data: Uint8ClampedArray | Uint8Array, width: number, height: number, channels: 1 | 2 | 3 | 4 | null = null) {\n    this.data = data;\n    this.width = width;\n    this.height = height;\n    if (channels !== null) {\n      this.channels = channels;\n    }\n    return this;\n  }\n\n  /**\n   * Clone the image\n   * @returns {RawImage} The cloned image\n   */\n  clone() {\n    return new RawImage(this.data.slice(), this.width, this.height, this.channels);\n  }\n\n  /**\n   * Helper method for converting image to have a certain number of channels\n   * @param {number} numChannels The number of channels. Must be 1, 3, or 4.\n   * @returns {RawImage} `this` to support chaining.\n   */\n  convert(numChannels: 1 | 3 | 4) {\n    if (this.channels === numChannels) return this; // Already correct number of channels\n\n    switch (numChannels) {\n      case 1:\n        this.grayscale();\n        break;\n      case 3:\n        this.rgb();\n        break;\n      case 4:\n        this.rgba();\n        break;\n      default:\n        throw new Error(`Conversion failed due to unsupported number of channels: ${this.channels}`);\n    }\n    return this;\n  }\n\n  /**\n   * Save the image to the given path.\n   * @param {string} path The path to save the image to.\n   */\n  async save(path: string) {\n    if (IS_BROWSER_OR_WEBWORKER) {\n      if (apis.IS_WEBWORKER_ENV) {\n        throw new Error('Unable to save an image from a Web Worker.');\n      }\n\n      const extension = path.split('.').pop()?.toLowerCase();\n      const mime = CONTENT_TYPE_MAP.get(extension as string) ?? 'image/png';\n\n      // Convert image to Blob\n      const blob = await this.toBlob(mime);\n\n      // Convert the canvas content to a data URL\n      const dataURL = URL.createObjectURL(blob);\n\n      // Create an anchor element with the data URL as the href attribute\n      const downloadLink = document.createElement('a');\n      downloadLink.href = dataURL;\n\n      // Set the download attribute to specify the desired filename for the downloaded image\n      downloadLink.download = path;\n\n      // Trigger the download\n      downloadLink.click();\n\n      // Clean up: remove the anchor element from the DOM\n      downloadLink.remove();\n    } else if (!env.useFS) {\n      throw new Error('Unable to save the image because filesystem is disabled in this environment.');\n    }\n  }\n\n  toSharp() {\n    if (IS_BROWSER_OR_WEBWORKER) {\n      throw new Error('toSharp() is only supported in server-side environments.');\n    }\n  }\n}\n\n/**\n * Helper function to load an image from a URL, path, etc.\n */\nexport const load_image = RawImage.read.bind(RawImage);\n","/**\n * The list of devices supported by Transformers.js\n */\nexport const DEVICE_TYPES = Object.freeze({\n  auto: 'auto', // Auto-detect based on device and environment\n  gpu: 'gpu', // Auto-detect GPU\n  cpu: 'cpu', // CPU\n  wasm: 'wasm', // WebAssembly\n  webgpu: 'webgpu', // WebGPU\n  cuda: 'cuda', // CUDA\n  dml: 'dml', // DirectML\n\n  webnn: 'webnn', // WebNN (default)\n  'webnn-npu': 'webnn-npu', // WebNN NPU\n  'webnn-gpu': 'webnn-gpu', // WebNN GPU\n  'webnn-cpu': 'webnn-cpu', // WebNN CPU\n});\n\n/**\n * @typedef {keyof typeof DEVICE_TYPES} DeviceType\n */\n","/// <reference types=\"@webgpu/types\" />\n\nimport { apis } from '../env';\n\nimport { DEVICE_TYPES } from './devices';\n\n// TODO: Use the adapter from `env.backends.onnx.webgpu.adapter` to check for `shader-f16` support,\n// when available in https://github.com/microsoft/onnxruntime/pull/19940.\n// For more information, see https://github.com/microsoft/onnxruntime/pull/19857#issuecomment-1999984753\n\n/**\n * Checks if WebGPU fp16 support is available in the current environment.\n */\nexport const isWebGpuFp16Supported = (function () {\n  /** @type {boolean} */\n  let cachedResult: boolean | undefined;\n\n  return async function () {\n    if (cachedResult === undefined) {\n      if (!apis.IS_WEBGPU_AVAILABLE) {\n        cachedResult = false;\n      } else {\n        try {\n          const adapter = await navigator.gpu.requestAdapter();\n          if (!adapter) {\n            cachedResult = false;\n          } else {\n            cachedResult = adapter.features.has('shader-f16');\n          }\n        } catch (e) {\n          cachedResult = false;\n        }\n      }\n    }\n    return cachedResult;\n  };\n})();\n\nexport const DATA_TYPES = Object.freeze({\n  auto: 'auto', // Auto-detect based on environment\n  fp32: 'fp32',\n  fp16: 'fp16',\n  q8: 'q8',\n  int8: 'int8',\n  uint8: 'uint8',\n  q4: 'q4',\n  bnb4: 'bnb4',\n  q4f16: 'q4f16', // fp16 model with int4 block weight quantization\n});\n/** @typedef {keyof typeof DATA_TYPES} DataType */\n\nexport const DEFAULT_DEVICE_DTYPE_MAPPING = Object.freeze({\n  // NOTE: If not specified, will default to fp32\n  [DEVICE_TYPES.wasm]: DATA_TYPES.q8,\n});\n\n/** @type {Record<Exclude<DataType, \"auto\">, string>} */\nexport const DEFAULT_DTYPE_SUFFIX_MAPPING = Object.freeze({\n  [DATA_TYPES.fp32]: '',\n  [DATA_TYPES.fp16]: '_fp16',\n  [DATA_TYPES.int8]: '_int8',\n  [DATA_TYPES.uint8]: '_uint8',\n  [DATA_TYPES.q8]: '_quantized',\n  [DATA_TYPES.q4]: '_q4',\n  [DATA_TYPES.q4f16]: '_q4f16',\n  [DATA_TYPES.bnb4]: '_bnb4',\n});\n\nexport type DeviceType = keyof typeof DEVICE_TYPES;\nexport type DataType = keyof typeof DATA_TYPES;","export const GITHUB_ISSUE_URL = 'https://github.com/sauravpanda/browserai/issues';\n\nexport const CONFIG_NAME = 'config.json';\nexport const FEATURE_EXTRACTOR_NAME = 'preprocessor_config.json';\nexport const IMAGE_PROCESSOR_NAME = 'preprocessor_config.json';\n\nexport const PROCESSOR_NAME = 'processor_config.json';\nexport const CHAT_TEMPLATE_NAME = 'chat_template.json';\nexport const GENERATION_CONFIG_NAME = 'generation_config.json';\n","/**\n * @module generation/logits_process\n */\n\nimport { Callable } from '../utils/generic';\nimport { Tensor } from '../utils/tensor';\n\nimport { max, log_softmax } from '../utils/maths';\nimport { GenerationConfig } from './configuration_utils';\nimport { WhisperGenerationConfig } from '../models/whisper/generation_whisper';\n\n/**\n * Abstract base class for all logit processors that can be applied during generation.\n */\nexport class LogitsProcessor extends Callable {\n  /**\n   * Apply the processor to the input logits.\n   *\n   * @abstract\n   * @param {bigint[][]} input_ids The input ids.\n   * @param {Tensor} logits The logits to process.\n   * @throws {Error} Throws an error if `_call` is not implemented in the subclass.\n   */\n  _call(input_ids: bigint[][], logits: Tensor): Tensor {\n    throw Error('`_call` should be implemented in a subclass');\n  }\n}\n\n/**\n * Abstract base class for all logit warpers that can be applied during generation with multinomial sampling.\n */\nexport class LogitsWarper extends Callable {\n  /**\n   * Apply the processor to the input logits.\n   *\n   * @abstract\n   * @param {bigint[][]} input_ids The input ids.\n   * @param {Tensor} logits The logits to process.\n   * @throws {Error} Throws an error if `_call` is not implemented in the subclass.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    throw Error('`_call` should be implemented in a subclass');\n  }\n}\n\n/**\n * A class representing a list of logits processors. A logits processor is a function that modifies the logits\n * output of a language model. This class provides methods for adding new processors and applying all processors to a\n * batch of logits.\n */\nexport class LogitsProcessorList extends Callable {\n  /**\n   * Constructs a new instance of `LogitsProcessorList`.\n   */\n  private processors: LogitsProcessor[] = [];\n  constructor() {\n    super();\n    this.processors = [];\n  }\n\n  /**\n   * Adds a new logits processor to the list.\n   *\n   * @param {LogitsProcessor} item The logits processor function to add.\n   */\n  push(item: LogitsProcessor) {\n    this.processors.push(item);\n  }\n\n  /**\n   * Adds multiple logits processors to the list.\n   *\n   * @param {LogitsProcessor[]} items The logits processor functions to add.\n   */\n  extend(items: LogitsProcessor[]) {\n    this.processors.push(...items);\n  }\n\n  /**\n   * Applies all logits processors in the list to a batch of logits, modifying them in-place.\n   *\n   * @param {bigint[][]} input_ids The input IDs for the language model.\n   * @param {Tensor} logits\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    let toReturn = logits;\n    // NOTE: Most processors modify logits inplace\n    for (const processor of this.processors) {\n      toReturn = processor._call(input_ids, toReturn);\n    }\n    return toReturn;\n  }\n\n  [Symbol.iterator]() {\n    return this.processors.values();\n  }\n}\n\n// DEPRECATED: https://github.com/huggingface/transformers/pull/29485\n// /**\n//  * A logits processor that forces a specific token to be generated by the decoder.\n//  */\n// export class ForceTokensLogitsProcessor extends LogitsProcessor {\n//     /**\n//      * Constructs a new instance of `ForceTokensLogitsProcessor`.\n//      *\n//      * @param {[number, number][]} forced_decoder_ids The ids of tokens that should be forced.\n//      */\n//     constructor(forced_decoder_ids) {\n//         super();\n//         // TODO: convert to `new Map(forced_decoder_ids)`\n//         this.force_token_map = Object.fromEntries(forced_decoder_ids ?? []);\n//     }\n\n//     /**\n//      * Apply the processor to the input logits.\n//      *\n//      * @param {bigint[][]} input_ids The input ids.\n//      * @param {Tensor} logits The logits to process.\n//      * @returns {Tensor} The processed logits.\n//      */\n//     _call(input_ids, logits) {\n//         console.log('this.force_token_map', this.force_token_map)\n//         console.log('call ForceTokensLogitsProcessor', input_ids, logits)\n//         console.log('input_ids.length', input_ids.length)\n//         let map = this.force_token_map[input_ids.length];\n//         if (map) { // There exists a mapping\n//             logits.data.fill(-Infinity)\n//             logits.data[map] = 0;\n//         }\n//         console.log('map', map)\n//         // throw Error(\"Not implemented\")\n//         return logits;\n//     }\n// }\n\n/**\n * A LogitsProcessor that forces a BOS token at the beginning of the generated sequence.\n */\nexport class ForcedBOSTokenLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a ForcedBOSTokenLogitsProcessor.\n   * @param {number} bos_token_id The ID of the beginning-of-sequence token to be forced.\n   */\n  bos_token_id: number;\n  constructor(bos_token_id: number) {\n    super();\n    this.bos_token_id = bos_token_id;\n  }\n\n  /**\n   * Apply the BOS token forcing to the logits.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The logits with BOS token forcing.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      if (input_ids[i].length === 1) {\n        const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n        (batch_logits_data as Float32Array).fill(-Infinity);\n        (batch_logits_data as Float32Array)[this.bos_token_id] = 0;\n      }\n    }\n    return logits;\n  }\n}\n\n/**\n * A logits processor that enforces the specified token as the last generated token when `max_length` is reached.\n */\nexport class ForcedEOSTokenLogitsProcessor extends LogitsProcessor {\n  max_length: number;\n  eos_token_id: number | number[];\n  /**\n   * Create a ForcedEOSTokenLogitsProcessor.\n   * @param {number} max_length The maximum length of the sequence to be generated.\n   * @param {number|number[]} eos_token_id The id(s) of the *end-of-sequence* token.\n   */\n  constructor(max_length: number, eos_token_id: number | number[]) {\n    super();\n    this.max_length = max_length;\n    this.eos_token_id = Array.isArray(eos_token_id) ? eos_token_id : [eos_token_id];\n  }\n\n  /**\n   * Apply the processor to input_ids and logits.\n   *\n   * @param {bigint[][]} input_ids The input ids.\n   * @param {Tensor} logits The logits tensor.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      if (input_ids[i].length === this.max_length - 1) {\n        const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n        (batch_logits_data as Float32Array).fill(-Infinity);\n        for (const eos_token of Array.isArray(this.eos_token_id) ? this.eos_token_id : [this.eos_token_id]) {\n          (batch_logits_data as Float32Array)[eos_token] = 0;\n        }\n      }\n    }\n    return logits;\n  }\n}\n\n/**\n * A LogitsProcessor that suppresses a list of tokens as soon as the `generate` function starts\n * generating using `begin_index` tokens. This should ensure that the tokens defined by\n * `begin_suppress_tokens` at not sampled at the begining of the generation.\n */\nexport class SuppressTokensAtBeginLogitsProcessor extends LogitsProcessor {\n  begin_suppress_tokens: number[];\n  begin_index: number;\n\n  /**\n   * Create a SuppressTokensAtBeginLogitsProcessor.\n   * @param {number[]} begin_suppress_tokens The IDs of the tokens to suppress.\n   * @param {number} begin_index The number of tokens to generate before suppressing tokens.\n   */\n  constructor(begin_suppress_tokens: number[], begin_index: number) {\n    super();\n    this.begin_suppress_tokens = begin_suppress_tokens;\n    this.begin_index = begin_index;\n  }\n\n  /**\n   * Apply the BOS token forcing to the logits.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The logits with BOS token forcing.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      if (input_ids[i].length === this.begin_index) {\n        const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n        for (const token_id of this.begin_suppress_tokens) {\n          batch_logits_data[token_id] = -Infinity;\n        }\n      }\n    }\n    return logits;\n  }\n}\n\n/**\n * A LogitsProcessor that handles adding timestamps to generated text.\n */\nexport class WhisperTimeStampLogitsProcessor extends LogitsProcessor {\n  /**\n   * Constructs a new WhisperTimeStampLogitsProcessor.\n   * @param {import('../models/whisper/generation_whisper.js').WhisperGenerationConfig} generate_config The config object passed to the `generate()` method of a transformer model.\n   * @param {number[]} init_tokens The initial tokens of the input sequence.\n   */\n  eos_token_id: number | number[];\n  no_timestamps_token_id: number | null;\n  timestamp_begin: number;\n  begin_index: number;\n  max_initial_timestamp_index: number;\n  constructor(generate_config: WhisperGenerationConfig, init_tokens: number[]) {\n    super();\n    this.eos_token_id = Array.isArray(generate_config.eos_token_id)\n      ? (generate_config.eos_token_id[0] ?? 0)\n      : (generate_config.eos_token_id ?? 0);\n\n    this.no_timestamps_token_id = generate_config.no_timestamps_token_id;\n    this.timestamp_begin = this.no_timestamps_token_id ? this.no_timestamps_token_id + 1 : 0;\n\n    this.begin_index = init_tokens.length;\n    if (init_tokens.at(-1) === this.no_timestamps_token_id) {\n      this.begin_index -= 1;\n    }\n    this.max_initial_timestamp_index = generate_config.max_initial_timestamp_index;\n  }\n\n  /**\n   * Modify the logits to handle timestamp tokens.\n   * @param {bigint[][]} input_ids The input sequence of tokens.\n   * @param {Tensor} logits The logits output by the model.\n   * @returns {Tensor} The modified logits.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n\n      // suppress <|notimestamps|> which is handled by without_timestamps\n      if (this.no_timestamps_token_id !== null) {\n        batch_logits_data[this.no_timestamps_token_id] = -Infinity;\n      }\n\n      if (input_ids[i].length === this.begin_index - 1) {\n        (batch_logits_data as Float32Array).fill(-Infinity);\n        (batch_logits_data as Float32Array)[this.timestamp_begin] = 0;\n        continue;\n      }\n\n      // timestamps have to appear in pairs, except directly before eos_token; mask logits accordingly\n      const seq = input_ids[i].slice(this.begin_index);\n      const last_was_timestamp = seq.length >= 1 && seq[seq.length - 1] >= this.timestamp_begin;\n      const penultimate_was_timestamp = seq.length < 2 || seq[seq.length - 2] >= this.timestamp_begin;\n\n      if (last_was_timestamp) {\n        if (penultimate_was_timestamp) {\n          // has to be non-timestamp\n          (batch_logits_data as Float32Array).subarray(this.timestamp_begin).fill(-Infinity);\n        } else {\n          // cannot be normal text tokens\n          const endToken = Array.isArray(this.eos_token_id) ? this.eos_token_id[0] : this.eos_token_id;\n          (batch_logits_data as Float32Array).subarray(0, endToken).fill(-Infinity);\n        }\n      }\n\n      // apply the `max_initial_timestamp` option\n      if (input_ids[i].length === this.begin_index && this.max_initial_timestamp_index !== null) {\n        const last_allowed = this.timestamp_begin + this.max_initial_timestamp_index;\n        (batch_logits_data as Float32Array).subarray(last_allowed + 1).fill(-Infinity);\n      }\n\n      // if sum of probability over timestamps is above any other token, sample timestamp\n      const logprobs = log_softmax(batch_logits_data as Float32Array);\n      const timestamp_logprob = Math.log(\n        (batch_logits_data as Float32Array)\n          .subarray(this.timestamp_begin)\n          .map(Math.exp)\n          .reduce((a, b) => a + b),\n      );\n      const max_text_token_logprob = max((logprobs as Float32Array).subarray(0, this.timestamp_begin))[0];\n\n      if (timestamp_logprob > max_text_token_logprob) {\n        (batch_logits_data as Float32Array).subarray(0, this.timestamp_begin).fill(-Infinity);\n      }\n    }\n\n    return logits;\n  }\n}\n\n/**\n * A logits processor that disallows ngrams of a certain size to be repeated.\n */\nexport class NoRepeatNGramLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a NoRepeatNGramLogitsProcessor.\n   * @param {number} no_repeat_ngram_size The no-repeat-ngram size. All ngrams of this size can only occur once.\n   */\n  no_repeat_ngram_size: number;\n  constructor(no_repeat_ngram_size: number) {\n    super();\n    this.no_repeat_ngram_size = no_repeat_ngram_size;\n  }\n\n  /**\n   * Generate n-grams from a sequence of token ids.\n   * @param {bigint[]} prevInputIds List of previous input ids\n   * @returns {Map<string, number[]>} Map of generated n-grams\n   */\n  getNgrams(prevInputIds: bigint[]) {\n    const curLen = prevInputIds.length;\n\n    /**@type {number[][]} */\n    const ngrams = [];\n    for (let j = 0; j < curLen + 1 - this.no_repeat_ngram_size; ++j) {\n      const ngram = [];\n      for (let k = 0; k < this.no_repeat_ngram_size; ++k) {\n        ngram.push(prevInputIds[j + k]);\n      }\n      ngrams.push(ngram.map(Number));\n    }\n\n    /** @type {Map<string, number[]>} */\n    const generatedNgram = new Map();\n    for (const ngram of ngrams) {\n      const prevNgram = ngram.slice(0, ngram.length - 1);\n      const prevNgramKey = JSON.stringify(prevNgram);\n      const prevNgramValue = generatedNgram.get(prevNgramKey) ?? [];\n      prevNgramValue.push(ngram[ngram.length - 1]);\n      generatedNgram.set(prevNgramKey, prevNgramValue);\n    }\n    return generatedNgram;\n  }\n\n  /**\n   * Generate n-grams from a sequence of token ids.\n   * @param {Map<string, number[]>} bannedNgrams Map of banned n-grams\n   * @param {bigint[]} prevInputIds List of previous input ids\n   * @returns {number[]} Map of generated n-grams\n   */\n  getGeneratedNgrams(bannedNgrams: Map<string, number[]>, prevInputIds: bigint[]) {\n    const ngramIdx = prevInputIds.slice(prevInputIds.length + 1 - this.no_repeat_ngram_size, prevInputIds.length);\n    const banned = bannedNgrams.get(JSON.stringify(ngramIdx.map(Number))) ?? [];\n    return banned;\n  }\n\n  /**\n   * Calculate banned n-gram tokens\n   * @param {bigint[]} prevInputIds List of previous input ids\n   * @returns {number[]} Map of generated n-grams\n   */\n  calcBannedNgramTokens(prevInputIds: bigint[]) {\n    const bannedTokens: number[] = [];\n    if (prevInputIds.length + 1 < this.no_repeat_ngram_size) {\n      // return no banned tokens if we haven't generated no_repeat_ngram_size tokens yet\n      return bannedTokens;\n    } else {\n      const generatedNgrams = this.getNgrams(prevInputIds);\n      const bannedTokens = this.getGeneratedNgrams(generatedNgrams, prevInputIds);\n      return bannedTokens;\n    }\n  }\n\n  /**\n   * Apply the no-repeat-ngram processor to the logits.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The logits with no-repeat-ngram processing.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n      const bannedTokens = this.calcBannedNgramTokens(input_ids[i]);\n      for (const token of bannedTokens) {\n        batch_logits_data[token] = -Infinity;\n      }\n    }\n    return logits;\n  }\n}\n\n/**\n * A logits processor that prevents the repetition of previous tokens through a penalty.\n * This penalty is applied at most once per token. Note that, for decoder-only models like most LLMs,\n * the considered tokens include the prompt.\n *\n * In the original [paper](https://arxiv.org/pdf/1909.05858.pdf), the authors suggest the use of a\n * penalty of around 1.2 to achieve a good balance between truthful generation and lack of repetition.\n * To penalize and reduce repetition, use `penalty` values above 1.0, where a higher value penalizes\n * more strongly. To reward and encourage repetition, use `penalty` values between 0.0 and 1.0, where\n * a lower value rewards more strongly.\n */\nexport class RepetitionPenaltyLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a RepetitionPenaltyLogitsProcessor.\n   * @param {number} penalty The parameter for repetition penalty.\n   * - 1.0 means no penalty. Above 1.0 penalizes previously generated tokens.\n   * - Between 0.0 and 1.0 rewards previously generated tokens.\n   */\n  penalty: number;\n  constructor(penalty: number) {\n    super();\n    this.penalty = penalty;\n  }\n\n  /**\n   * Apply the repetition penalty to the logits.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The logits with repetition penalty processing.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n      for (const input_id of new Set(input_ids[i])) {\n        const token = Number(input_id);\n        if (batch_logits_data[token] < 0) {\n          batch_logits_data[token] *= this.penalty;\n        } else {\n          batch_logits_data[token] /= this.penalty;\n        }\n      }\n    }\n\n    return logits;\n  }\n}\n\n/**\n * A logits processor that enforces a minimum number of tokens.\n */\nexport class MinLengthLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a MinLengthLogitsProcessor.\n   * @param {number} min_length The minimum length below which the score of `eos_token_id` is set to negative infinity.\n   * @param {number|number[]} eos_token_id The ID/IDs of the end-of-sequence token.\n   */\n  min_length: number;\n  eos_token_id: number | number[];\n  constructor(min_length: number, eos_token_id: number | number[]) {\n    super();\n    this.min_length = min_length;\n    this.eos_token_id = Array.isArray(eos_token_id) ? eos_token_id : [eos_token_id];\n  }\n\n  /**\n   * Apply logit processor.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The processed logits.\n   */\n\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      if (input_ids[i].length < this.min_length) {\n        const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n\n        for (const eos_token of Array.isArray(this.eos_token_id) ? this.eos_token_id : [this.eos_token_id]) {\n          batch_logits_data[eos_token] = -Infinity;\n        }\n      }\n    }\n\n    return logits;\n  }\n}\n\n/**\n * A logits processor that enforces a minimum number of new tokens.\n */\nexport class MinNewTokensLengthLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a MinNewTokensLengthLogitsProcessor.\n   * @param {number} prompt_length_to_skip The input tokens length.\n   * @param {number} min_new_tokens The minimum *new* tokens length below which the score of `eos_token_id` is set to negative infinity.\n   * @param {number|number[]} eos_token_id The ID/IDs of the end-of-sequence token.\n   */\n  prompt_length_to_skip: number;\n  min_new_tokens: number;\n  eos_token_id: number | number[];\n  constructor(prompt_length_to_skip: number, min_new_tokens: number, eos_token_id: number | number[]) {\n    super();\n    this.prompt_length_to_skip = prompt_length_to_skip;\n    this.min_new_tokens = min_new_tokens;\n    this.eos_token_id = Array.isArray(eos_token_id) ? eos_token_id : [eos_token_id];\n  }\n\n  /**\n   * Apply logit processor.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The processed logits.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      const new_tokens_length = input_ids[i].length - this.prompt_length_to_skip;\n      if (new_tokens_length < this.min_new_tokens) {\n        const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n\n        for (const eos_token of Array.isArray(this.eos_token_id) ? this.eos_token_id : [this.eos_token_id]) {\n          batch_logits_data[eos_token] = -Infinity;\n        }\n      }\n    }\n    return logits;\n  }\n}\n\nexport class NoBadWordsLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a `NoBadWordsLogitsProcessor`.\n   * @param {number[][]} bad_words_ids List of list of token ids that are not allowed to be generated.\n   * @param {number|number[]} eos_token_id The id of the *end-of-sequence* token. Optionally, use a list to set multiple *end-of-sequence* tokens.\n   */\n  bad_words_ids: number[][];\n  eos_token_id: number | number[];\n  constructor(bad_words_ids: number[][], eos_token_id: number | number[]) {\n    super();\n    this.bad_words_ids = bad_words_ids;\n    this.eos_token_id = Array.isArray(eos_token_id) ? eos_token_id : [eos_token_id];\n  }\n\n  /**\n   * Apply logit processor.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The processed logits.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    for (let i = 0; i < input_ids.length; ++i) {\n      const batch_logits_data = /** @type {Float32Array} */ logits[i].data;\n      const ids = input_ids[i];\n      for (const bad_word_ids of this.bad_words_ids) {\n        // Whether to modify the logits of the last token in the bad word id sequence\n        let mark = true;\n\n        // For each bad word in the list, if the current sequence of input ids ends with this sequence (excluding the last),\n        // then we set the logits of the last bad word id to -Infinity.\n        for (let j = 1; j <= bad_word_ids.length - 1 && bad_word_ids.length < ids.length; ++j) {\n          // NOTE: We use != instead of !== to compare bigint and number\n          // @ts-ignore\n          if (bad_word_ids.at(-j - 1) != ids.at(-j)) {\n            // We have found a mismatch\n            mark = false;\n            break;\n          }\n        }\n        if (mark) {\n          const lastId = bad_word_ids.at(-1);\n          if (lastId !== undefined) {\n            batch_logits_data[lastId] = -Infinity;\n          }\n        }\n      }\n    }\n    return logits;\n  }\n}\n\n/**\n * [`LogitsProcessor`] for classifier free guidance (CFG). The scores are split over the batch dimension,\n * where the first half correspond to the conditional logits (predicted from the input prompt) and the second half\n * correspond to the unconditional logits (predicted from an empty or 'null' prompt). The processor computes a\n * weighted average across the conditional and unconditional logits, parameterised by the `guidance_scale`.\n *\n * See [the paper](https://arxiv.org/abs/2306.05284) for more information.\n */\nexport class ClassifierFreeGuidanceLogitsProcessor extends LogitsProcessor {\n  /**\n   * Create a `ClassifierFreeGuidanceLogitsProcessor`.\n   * @param {number} guidance_scale The guidance scale for classifier free guidance (CFG). CFG is enabled by setting `guidance_scale > 1`.\n   * Higher guidance scale encourages the model to generate samples that are more closely linked to the input\n   * prompt, usually at the expense of poorer quality.\n   */\n  guidance_scale: number;\n  constructor(guidance_scale: number) {\n    super();\n    if (guidance_scale <= 1) {\n      throw new Error(\n        `Require guidance scale >1 to use the classifier free guidance processor, got guidance scale ${guidance_scale}.`,\n      );\n    }\n    this.guidance_scale = guidance_scale;\n  }\n\n  /**\n   * Apply logit processor.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The processed logits.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    if (logits.dims[0] !== 2 * input_ids.length) {\n      throw new Error(\n        `Logits should have twice the batch size of the input ids, the first half of batches corresponding to ` +\n          `the conditional inputs, and the second half of batches corresponding to the unconditional inputs. Got ` +\n          `batch size ${logits.dims[0]} for the logits and ${input_ids.length} for the input ids.`,\n      );\n    }\n\n    const unguided_bsz = input_ids.length;\n    const cond_logits = logits.slice([0, unguided_bsz], null);\n    const uncond_logits = logits.slice([unguided_bsz, logits.dims[0]], null);\n\n    // Merge into uncond_logits (to save memory). This is equivalent to the following:\n    // scores = uncond_logits + (cond_logits - uncond_logits) * guidance_scale\n    for (let i = 0; i < uncond_logits.data.length; ++i) {\n      uncond_logits.data[i] += (cond_logits.data[i] - uncond_logits.data[i]) * this.guidance_scale;\n    }\n\n    return uncond_logits;\n  }\n}\n\n/**\n * [`LogitsWarper`] for temperature (exponential scaling output probability distribution), which effectively means\n * that it can control the randomness of the predicted tokens. Often used together with [`TopPLogitsWarper`] and [`TopKLogitsWarper`].\n */\nexport class TemperatureLogitsWarper extends LogitsWarper {\n  /**\n   * Create a `TemperatureLogitsWarper`.\n   * @param {number} temperature Strictly positive float value used to modulate the logits distribution.\n   * A value smaller than `1` decreases randomness (and vice versa), with `0` being equivalent to shifting\n   * all probability mass to the most likely token.\n   */\n  temperature: number;\n  constructor(temperature: number) {\n    super();\n\n    if (typeof temperature !== 'number' || temperature <= 0) {\n      let errorMessage = `\\`temperature\\` (=${temperature}) must be a strictly positive float, otherwise your next token scores will be invalid.`;\n\n      if (temperature === 0) {\n        errorMessage += \" If you're looking for greedy decoding strategies, set `do_sample=false`.\";\n      }\n    }\n    this.temperature = temperature;\n  }\n\n  /**\n   * Apply logit warper.\n   * @param {bigint[][]} input_ids The input IDs.\n   * @param {Tensor} logits The logits.\n   * @returns {Tensor} The processed logits.\n   */\n  _call(input_ids: bigint[][], logits: Tensor) {\n    const batch_logits_data = /** @type {Float32Array} */ logits.data;\n    for (let i = 0; i < batch_logits_data.length; ++i) {\n      batch_logits_data[i] /= this.temperature;\n    }\n    return logits;\n  }\n}\n\n/**\n * [`LogitsWarper`] that performs top-p, i.e. restricting to top tokens summing to prob_cut_off <= prob_cut_off.\n * Often used together with [`TemperatureLogitsWarper`] and [`TopKLogitsWarper`].\n */\nexport class TopPLogitsWarper extends LogitsWarper {\n  /**\n   * Create a `TopPLogitsWarper`.\n   * @param {number} top_p If set to < 1, only the smallest set of most probable tokens with\n   * probabilities that add up to `top_p` or higher are kept for generation.\n   * @param {Object} options Additional options for the top-p sampling.\n   * @param {number} [options.filter_value=-Infinity] All filtered values will be set to this float value.\n   * @param {number} [options.min_tokens_to_keep=1] Minimum number of tokens that cannot be filtered.\n   */\n  top_p: number;\n  filter_value: number;\n  min_tokens_to_keep: number;\n  constructor(top_p: number, { filter_value = -Infinity, min_tokens_to_keep = 1 } = {}) {\n    super();\n    if (top_p < 0 || top_p > 1.0) {\n      throw new Error(`\\`top_p\\` must be a float > 0 and < 1, but is ${top_p}`);\n    }\n    if (!Number.isInteger(min_tokens_to_keep) || min_tokens_to_keep < 1) {\n      throw new Error(`\\`min_tokens_to_keep\\` must be a positive integer, but is ${min_tokens_to_keep}`);\n    }\n\n    this.top_p = top_p;\n    this.filter_value = filter_value;\n    this.min_tokens_to_keep = min_tokens_to_keep;\n  }\n}\n\n/**\n * [`LogitsWarper`] that performs top-k, i.e. restricting to the k highest probability elements.\n * Often used together with [`TemperatureLogitsWarper`] and [`TopPLogitsWarper`].\n */\nexport class TopKLogitsWarper extends LogitsWarper {\n  /**\n   * Create a `TopKLogitsWarper`.\n   * @param {number} top_k If set to > 0, only the top `top_k` tokens are kept for generation.\n   * @param {Object} options Additional options for the top-k sampling.\n   * @param {number} [options.filter_value=-Infinity] All filtered values will be set to this float value.\n   * @param {number} [options.min_tokens_to_keep=1] Minimum number of tokens that cannot be filtered.\n   */\n  top_k: number;\n  filter_value: number;\n  constructor(top_k: number, { filter_value = -Infinity, min_tokens_to_keep = 1 } = {}) {\n    super();\n    if (!Number.isInteger(top_k) || top_k < 0) {\n      throw new Error(`\\`top_k\\` must be a positive integer, but is ${top_k}`);\n    }\n\n    this.top_k = Math.max(top_k, min_tokens_to_keep);\n    this.filter_value = filter_value;\n  }\n}\n","/**\n * @module generation/configuration_utils\n */\n\nimport { PretrainedConfig } from '../configs';\nimport { pick } from '../utils/core';\nimport { TextStreamer } from './streamers';\n\n/**\n * Class that holds a configuration for a generation task.\n */\nexport class GenerationConfig {\n  // Parameters that control the length of the output\n  /**\n   * The maximum length the generated tokens can have.\n   * Corresponds to the length of the input prompt + `max_new_tokens`.\n   * Its effect is overridden by `max_new_tokens`, if also set.\n   * @type {number}\n   * @default 20\n   */\n  max_length: number = 20;\n\n  /**\n   * The maximum numbers of tokens to generate, ignoring the number of tokens in the prompt.\n   * @type {number}\n   * @default null\n   */\n  max_new_tokens: number | null = null;\n\n  /**\n   * The minimum length of the sequence to be generated.\n   * Corresponds to the length of the input prompt + `min_new_tokens`.\n   * Its effect is overridden by `min_new_tokens`, if also set.\n   * @type {number}\n   * @default 0\n   */\n  min_length: number = 0;\n\n  /**\n   * The minimum numbers of tokens to generate, ignoring the number of tokens in the prompt.\n   * @type {number}\n   * @default null\n   */\n  min_new_tokens: number | null = null;\n\n  /**\n   * Controls the stopping condition for beam-based methods, like beam-search. It accepts the following values:\n   * - `true`, where the generation stops as soon as there are `num_beams` complete candidates;\n   * - `false`, where an heuristic is applied and the generation stops when is it very unlikely to find better candidates;\n   * - `\"never\"`, where the beam search procedure only stops when there cannot be better candidates (canonical beam search algorithm).\n   * @type {boolean|\"never\"}\n   * @default false\n   */\n  early_stopping: boolean | 'never' = false;\n\n  /**\n   * The maximum amount of time you allow the computation to run for in seconds.\n   * Generation will still finish the current pass after allocated time has been passed.\n   * @type {number}\n   * @default null\n   */\n  max_time: number | null = null;\n\n  // Parameters that control the generation strategy used\n  /**\n   * Whether or not to use sampling; use greedy decoding otherwise.\n   * @type {boolean}\n   * @default false\n   */\n  do_sample: boolean = false;\n\n  /**\n   * Number of beams for beam search. 1 means no beam search.\n   * @type {number}\n   * @default 1\n   */\n  num_beams: number = 1;\n\n  /**\n   * Number of groups to divide `num_beams` into in order to ensure diversity among different groups of beams.\n   * See [this paper](https://arxiv.org/pdf/1610.02424.pdf) for more details.\n   * @type {number}\n   * @default 1\n   */\n  num_beam_groups: number = 1;\n\n  /**\n   * The values balance the model confidence and the degeneration penalty in contrastive search decoding.\n   * @type {number}\n   * @default null\n   */\n  penalty_alpha: number | null = null;\n\n  /**\n   * Whether or not the model should use the past last key/values attentions (if applicable to the model) to speed up decoding.\n   * @type {boolean}\n   * @default true\n   */\n  use_cache: boolean = true;\n\n  // Parameters for manipulation of the model output logits\n  /**\n   * The value used to modulate the next token probabilities.\n   * @type {number}\n   * @default 1.0\n   */\n  temperature: number = 1.0;\n\n  /**\n   * The number of highest probability vocabulary tokens to keep for top-k-filtering.\n   * @type {number}\n   * @default 50\n   */\n  top_k: number = 50;\n\n  /**\n   * If set to float < 1, only the smallest set of most probable tokens with probabilities that add up to `top_p` or higher are kept for generation.\n   * @type {number}\n   * @default 1.0\n   */\n  top_p: number = 1.0;\n\n  /**\n   * Local typicality measures how similar the conditional probability of predicting a target token next is to the expected conditional probability of predicting a random token next, given the partial text already generated.\n   * If set to float < 1, the smallest set of the most locally typical tokens with probabilities that add up to `typical_p` or higher are kept for generation.\n   * See [this paper](https://arxiv.org/pdf/2202.00666.pdf) for more details.\n   * @type {number}\n   * @default 1.0\n   */\n  typical_p: number = 1.0;\n\n  /**\n   * If set to float strictly between 0 and 1, only tokens with a conditional probability greater than `epsilon_cutoff` will be sampled.\n   * In the paper, suggested values range from 3e-4 to 9e-4, depending on the size of the model.\n   * See [Truncation Sampling as Language Model Desmoothing](https://arxiv.org/abs/2210.15191) for more details.\n   * @type {number}\n   * @default 0.0\n   */\n  epsilon_cutoff: number = 0.0;\n\n  /**\n   * Eta sampling is a hybrid of locally typical sampling and epsilon sampling.\n   * If set to float strictly between 0 and 1, a token is only considered if it is greater than either `eta_cutoff` or `sqrt(eta_cutoff) * exp(-entropy(softmax(next_token_logits)))`.\n   * The latter term is intuitively the expected next token probability, scaled by `sqrt(eta_cutoff)`. In the paper, suggested values range from 3e-4 to 2e-3, depending on the size of the model.\n   * See [Truncation Sampling as Language Model Desmoothing](https://arxiv.org/abs/2210.15191) for more details.\n   * @type {number}\n   * @default 0.0\n   */\n  eta_cutoff: number = 0.0;\n\n  /**\n   * This value is subtracted from a beam's score if it generates a token same as any beam from other group at a particular time.\n   * Note that `diversity_penalty` is only effective if `group beam search` is enabled.\n   * @type {number}\n   * @default 0.0\n   */\n  diversity_penalty: number = 0.0;\n\n  /**\n   * The parameter for repetition penalty. 1.0 means no penalty.\n   * See [this paper](https://arxiv.org/pdf/1909.05858.pdf) for more details.\n   * @type {number}\n   * @default 1.0\n   */\n  repetition_penalty: number = 1.0;\n\n  /**\n   * The paramater for encoder_repetition_penalty.\n   * An exponential penalty on sequences that are not in the original input.\n   * 1.0 means no penalty.\n   * @type {number}\n   * @default 1.0\n   */\n  encoder_repetition_penalty: number = 1.0;\n\n  /**\n   * Exponential penalty to the length that is used with beam-based generation.\n   * It is applied as an exponent to the sequence length, which in turn is used to divide the score of the sequence.\n   * Since the score is the log likelihood of the sequence (i.e. negative), `length_penalty` > 0.0 promotes longer sequences, while `length_penalty` < 0.0 encourages shorter sequences.\n   * @type {number}\n   * @default 1.0\n   */\n  length_penalty: number = 1.0;\n\n  /**\n   * If set to int > 0, all ngrams of that size can only occur once.\n   * @type {number}\n   * @default 0\n   */\n  no_repeat_ngram_size: number = 0;\n\n  /**\n   * List of token ids that are not allowed to be generated.\n   * In order to get the token ids of the words that should not appear in the generated text, use\n   * `tokenizer(bad_words, { add_prefix_space: true, add_special_tokens: false }).input_ids`.\n   * @type {number[][]}\n   * @default null\n   */\n  bad_words_ids: number[][] | null = null;\n\n  /**\n   * List of token ids that must be generated.\n   * If given a `number[][]`, this is treated as a simple list of words that must be included, the opposite to `bad_words_ids`.\n   * If given `number[][][]`, this triggers a [disjunctive constraint](https://github.com/huggingface/transformers/issues/14081), where one can allow different forms of each word.\n   * @type {number[][]|number[][][]}\n   * @default null\n   */\n  force_words_ids: number[][] | number[][][] | null  = null;\n\n  /**\n   * Whether to renormalize the logits after applying all the logits processors or warpers (including the custom ones).\n   * It's highly recommended to set this flag to `true` as the search algorithms suppose the score logits are normalized but some logit processors or warpers break the normalization.\n   * @type {boolean}\n   * @default false\n   */\n  renormalize_logits: boolean = false;\n\n  /**\n   * Custom constraints that can be added to the generation to ensure that the output will contain the use of certain tokens as defined by `Constraint` objects, in the most sensible way possible.\n   * @type {Object[]}\n   * @default null\n   */\n  constraints: Object[] | null = null;\n\n  /**\n   * The id of the token to force as the first generated token after the `decoder_start_token_id`.\n   * Useful for multilingual models like mBART where the first generated token needs to be the target language token.\n   * @type {number}\n   * @default null\n   */\n  forced_bos_token_id: number | null = null;\n\n  /**\n   * The id of the token to force as the last generated token when `max_length` is reached.\n   * Optionally, use a list to set multiple *end-of-sequence* tokens.\n   * @type {number|number[]}\n   * @default null\n   */\n  forced_eos_token_id: number | number[] | null = null;\n\n  /**\n   * Whether to remove possible *nan* and *inf* outputs of the model to prevent the generation method to crash. Note that using `remove_invalid_values` can slow down generation.\n   * @type {boolean}\n   */\n  remove_invalid_values: boolean = false;\n\n  /**\n   * This Tuple adds an exponentially increasing length penalty, after a certain amount of tokens have been generated.\n   * The tuple shall consist of: `(start_index, decay_factor)` where `start_index` indicates where penalty starts and `decay_factor` represents the factor of exponential decay.\n   * @type {[number, number]}\n   * @default null\n   */\n  exponential_decay_length_penalty: [number, number] | null = null;\n\n  /**\n   * A list of tokens that will be suppressed at generation.\n   * The `SuppressTokens` logit processor will set their log probs to `-inf` so that they are not sampled.\n   * @type {number[]}\n   * @default null\n   */\n  suppress_tokens: number[] | null = null;\n\n  /**\n   * A streamer that will be used to stream the generation.\n   * @type {import('./streamers.js').TextStreamer}\n   * @default null\n   */\n  streamer: TextStreamer | null = null;\n\n  /**\n   * A list of tokens that will be suppressed at the beginning of the generation.\n   * The `SuppressBeginTokens` logit processor will set their log probs to `-inf` so that they are not sampled.\n   * @type {number[]}\n   * @default null\n   */\n  begin_suppress_tokens: number[] | null = null;\n\n  /**\n   * A list of pairs of integers which indicates a mapping from generation indices to token indices that will be forced before sampling.\n   * For example, `[[1, 123]]` means the second generated token will always be a token of index 123.\n   * @type {[number, number][]}\n   * @default null\n   */\n  forced_decoder_ids: [number, number][] | null = null;\n\n  /**\n   * The guidance scale for classifier free guidance (CFG). CFG is enabled by setting `guidance_scale > 1`.\n   * Higher guidance scale encourages the model to generate samples that are more closely linked to the input\n   * prompt, usually at the expense of poorer quality.\n   * @type {number}\n   * @default null\n   */\n  guidance_scale: number | null = null;\n\n  // Parameters that define the output variables of `generate`\n  /**\n   * The number of independently computed returned sequences for each element in the batch.\n   * @type {number}\n   * @default 1\n   */\n  num_return_sequences: number = 1;\n\n  /**\n   * Whether or not to return the attentions tensors of all attention layers.\n   * See `attentions` under returned tensors for more details.\n   * @type {boolean}\n   * @default false\n   */\n  output_attentions: boolean = false;\n\n  /**\n   * Whether or not to return the hidden states of all layers.\n   * See `hidden_states` under returned tensors for more details.\n   * @type {boolean}\n   * @default false\n   */\n  output_hidden_states: boolean = false;\n\n  /**\n   * Whether or not to return the prediction scores.\n   * See `scores` under returned tensors for more details.\n   * @type {boolean}\n   * @default false\n   */\n  output_scores: boolean = false;\n\n  /**\n   * Whether or not to return a `ModelOutput` instead of a plain tuple.\n   * @type {boolean}\n   * @default false\n   */\n  return_dict_in_generate: boolean = false;\n\n  // Special tokens that can be used at generation time\n  /**\n   * The id of the *padding* token.\n   * @type {number}\n   * @default null\n   */\n  pad_token_id: number | null = null;\n\n  /**\n   * The id of the *beginning-of-sequence* token.\n   * @type {number}\n   * @default null\n   */\n  bos_token_id: number | null = null;\n\n  /**\n   * The id of the *end-of-sequence* token.\n   * Optionally, use a list to set multiple *end-of-sequence* tokens.\n   * @type {number|number[]}\n   * @default null\n   */\n  eos_token_id: number | number[] | null = null;\n\n  // Generation parameters exclusive to encoder-decoder models\n  /**\n   * If set to int > 0, all ngrams of that size that occur in the `encoder_input_ids` cannot occur in the `decoder_input_ids`.\n   * @type {number}\n   * @default 0\n   */\n  encoder_no_repeat_ngram_size: number = 0;\n\n  /**\n   * If an encoder-decoder model starts decoding with a different token than *bos*, the id of that token.\n   * @type {number}\n   * @default null\n   */\n  decoder_start_token_id: number | null = null;\n\n  // Wild card\n  /**\n   * Additional generation kwargs will be forwarded to the `generate` function of the model.\n   * Kwargs that are not present in `generate`'s signature will be used in the model forward pass.\n   * @type {Object}\n   * @default {}\n   */\n  generation_kwargs: Object = {};\n\n  /**\n   *\n   * @param {GenerationConfig|import('../configs.js').PretrainedConfig} config\n   */\n  constructor(config: GenerationConfig | PretrainedConfig) {\n    Object.assign(this, pick(config, Object.getOwnPropertyNames(this) as any));\n  }\n}\n","/**\n * @module generation/stopping_criteria\n */\n\nimport { Callable } from '../utils/generic.js';\n\n// NOTE:\n// Stopping Criteria returns a list of `batch_size` booleans, indicating whether each sequence in the batch should be stopped.\n\n/**\n * Abstract base class for all stopping criteria that can be applied during generation.\n */\nexport class StoppingCriteria extends Callable {\n  /**\n   *\n   * @param {number[][]} input_ids (`number[][]` of shape `(batch_size, sequence_length)`):\n   * Indices of input sequence tokens in the vocabulary.\n   * @param {number[][]} scores scores (`number[][]` of shape `(batch_size, config.vocab_size)`):\n   * Prediction scores of a language modeling head. These can be scores for each vocabulary token before SoftMax\n   * or scores for each vocabulary token after SoftMax.\n   * @returns {boolean[]} A list of booleans indicating whether each sequence should be stopped.\n   */\n  _call(input_ids: number[][], scores: number[][]) {\n    throw Error('StoppingCriteria needs to be subclassed');\n  }\n}\n/**\n */\nexport class StoppingCriteriaList extends Callable {\n  /**\n   * Constructs a new instance of `StoppingCriteriaList`.\n   */\n  criteria: StoppingCriteria[];\n  constructor() {\n    super();\n    this.criteria = [];\n  }\n\n  /**\n   * Adds a new stopping criterion to the list.\n   *\n   * @param {StoppingCriteria} item The stopping criterion to add.\n   */\n  push(item: StoppingCriteria) {\n    this.criteria.push(item);\n  }\n\n  /**\n   * Adds multiple stopping criteria to the list.\n   *\n   * @param {StoppingCriteria|StoppingCriteriaList|StoppingCriteria[]} items The stopping criteria to add.\n   */\n  extend(items: StoppingCriteria | StoppingCriteriaList | StoppingCriteria[]) {\n    if (items instanceof StoppingCriteriaList) {\n      items = items.criteria;\n    } else if (items instanceof StoppingCriteria) {\n      items = [items];\n    }\n    this.criteria.push(...items);\n  }\n\n  _call(input_ids: number[][], scores: number[][]) {\n    const is_done = new Array(input_ids.length).fill(false);\n    for (const criterion of this.criteria) {\n      const criterion_done = criterion._call(input_ids, scores);\n      for (let i = 0; i < is_done.length; ++i) {\n        is_done[i] ||= (criterion_done as any)[i];\n      }\n    }\n    return is_done;\n  }\n\n  [Symbol.iterator]() {\n    return this.criteria.values();\n  }\n}\n\n/**\n * This class can be used to stop generation whenever the full generated number of tokens exceeds `max_length`.\n * Keep in mind for decoder-only type of transformers, this will include the initial prompted tokens.\n */\nexport class MaxLengthCriteria extends StoppingCriteria {\n  /**\n   *\n   * @param {number} max_length The maximum length that the output sequence can have in number of tokens.\n   * @param {number} [max_position_embeddings=null] The maximum model length, as defined by the model's `config.max_position_embeddings` attribute.\n   */\n  max_length: number;\n  max_position_embeddings: number | null;\n  constructor(max_length: number, max_position_embeddings: number | null = null) {\n    super();\n    this.max_length = max_length;\n    this.max_position_embeddings = max_position_embeddings;\n  }\n\n  _call(input_ids: number[][]) {\n    return input_ids.map((ids) => ids.length >= this.max_length);\n  }\n}\n\n// TODO: add MaxTimeCriteria\n\n/**\n * This class can be used to stop generation whenever the \"end-of-sequence\" token is generated.\n * By default, it uses the `model.generation_config.eos_token_id`.\n */\nexport class EosTokenCriteria extends StoppingCriteria {\n  /**\n   *\n   * @param {number|number[]} eos_token_id The id of the *end-of-sequence* token.\n   * Optionally, use a list to set multiple *end-of-sequence* tokens.\n   */\n  eos_token_id: number | number[];\n  constructor(eos_token_id: number | number[]) {\n    super();\n    if (!Array.isArray(eos_token_id)) {\n      eos_token_id = [eos_token_id];\n    }\n    this.eos_token_id = eos_token_id;\n  }\n\n  /**\n   *\n   * @param {number[][]} input_ids\n   * @param {number[][]} scores\n   * @returns {boolean[]}\n   */\n  _call(input_ids: number[][], scores: number[][]) {\n    return input_ids.map((ids) => {\n      const last = ids.at(-1);\n      // NOTE: We use == instead of === to allow for number/bigint comparison\n      if (Array.isArray(this.eos_token_id)) {\n        return this.eos_token_id.some((eos_id: number) => last == eos_id);\n      } else {\n        return last == this.eos_token_id;\n      }\n    });\n  }\n}\n\n/**\n * This class can be used to stop generation whenever the user interrupts the process.\n */\nexport class InterruptableStoppingCriteria extends StoppingCriteria {\n  interrupted: boolean;\n  constructor() {\n    super();\n    this.interrupted = false;\n  }\n\n  interrupt() {\n    this.interrupted = true;\n  }\n\n  reset() {\n    this.interrupted = false;\n  }\n\n  _call(input_ids: number[][], scores: number[][]) {\n    return new Array(input_ids.length).fill(this.interrupted);\n  }\n}\n","/**\n * @module generation/logits_sampler\n */\n\nimport { Callable } from '../utils/generic';\nimport { Tensor, topk } from '../utils/tensor';\n\nimport { max, softmax } from '../utils/maths';\nimport { GenerationConfig } from './configuration_utils.js';\n\ntype TypedArray =\n  | Int8Array\n  | Uint8Array\n  | Uint8ClampedArray\n  | Int16Array\n  | Uint16Array\n  | Int32Array\n  | Uint32Array\n  | Float32Array\n  | Float64Array;\n\n/**\n * Sampler is a base class for all sampling methods used for text generation.\n */\nexport class LogitsSampler extends Callable {\n  /**\n   * Creates a new Sampler object with the specified generation config.\n   * @param {GenerationConfig} generation_config The generation config.\n   */\n  generation_config: GenerationConfig;\n  constructor(generation_config: GenerationConfig) {\n    super();\n    this.generation_config = generation_config;\n  }\n\n  /**\n   * Executes the sampler, using the specified logits.\n   * @param {Tensor} logits\n   * @returns {Promise<[bigint, number][]>}\n   */\n  async _call(logits: Tensor) {\n    // Sample from logits, of dims [batch, sequence_length, vocab_size].\n    // If index is specified, sample from [batch, index, vocab_size].\n    return this.sample(logits);\n  }\n\n  /**\n   * Abstract method for sampling the logits.\n   * @param {Tensor} logits\n   * @throws {Error} If not implemented in subclass.\n   * @returns {Promise<[bigint, number][]>}\n   */\n  async sample(logits: Tensor): Promise<[bigint, number][]> {\n    throw Error('sample should be implemented in subclasses.');\n  }\n\n  /**\n   * Returns the specified logits as an array, with temperature applied.\n   * @param {Tensor} logits\n   * @param {number} index\n   * @returns {Float32Array}\n   */\n  getLogits(logits: Tensor, index: number) {\n    let vocabSize = logits.dims.at(-1);\n\n    let logs = /** @type {Float32Array} */ logits.data;\n\n    if (index === -1) {\n      logs = logs.slice(-vocabSize);\n    } else {\n      let startIndex = index * vocabSize;\n      logs = logs.slice(startIndex, startIndex + vocabSize);\n    }\n    return logs;\n  }\n\n  /**\n   * Selects an item randomly based on the specified probabilities.\n   * @param {import(\"../transformers.js\").DataArray} probabilities An array of probabilities to use for selection.\n   * @returns {number} The index of the selected item.\n   */\n  randomSelect(probabilities: Float32Array) {\n    // Return index of chosen item\n    let sumProbabilities = 0;\n    for (let i = 0; i < probabilities.length; ++i) {\n      sumProbabilities += probabilities[i];\n    }\n\n    let r = Math.random() * sumProbabilities;\n    for (let i = 0; i < probabilities.length; ++i) {\n      r -= probabilities[i];\n      if (r <= 0) {\n        return i;\n      }\n    }\n    return 0; // return first (most probable) as a fallback\n  }\n\n  /**\n   * Returns a Sampler object based on the specified options.\n   * @param {GenerationConfig} generation_config An object containing options for the sampler.\n   * @returns {LogitsSampler} A Sampler object.\n   */\n  static getSampler(generation_config: GenerationConfig) {\n    // - *greedy decoding*: `num_beams=1` and `do_sample=False`\n    // - *contrastive search*: `penalty_alpha>0` and `top_k>1`\n    // - *multinomial sampling*: `num_beams=1` and `do_sample=True`\n    // - *beam-search decoding*: `num_beams>1` and `do_sample=False`\n    // - *beam-search multinomial sampling*: `num_beams>1` and `do_sample=True`\n    // - *diverse beam-search decoding*: `num_beams>1` and `num_beam_groups>1`\n    // - *constrained beam-search decoding*: `constraints!=None` or `force_words_ids!=None`\n\n    // NOTE: beam search is implemented directly into the generation function\n    if (generation_config.do_sample) {\n      return new MultinomialSampler(generation_config);\n    } else if (generation_config.num_beams > 1) {\n      return new BeamSearchSampler(generation_config);\n    } else {\n      if (generation_config.num_return_sequences > 1) {\n        throw Error(\n          `num_return_sequences has to be 1 when doing greedy search, but is ${generation_config.num_return_sequences}.`,\n        );\n      }\n      return new GreedySampler(generation_config);\n    }\n  }\n}\n\n/**\n * Class representing a Greedy Sampler.\n */\nclass GreedySampler extends LogitsSampler {\n  /**\n   * Sample the maximum probability of a given logits tensor.\n   * @param {Tensor} logits\n   * @returns {Promise<[bigint, number][]>} An array with a single tuple, containing the index of the maximum value and a meaningless score (since this is a greedy search).\n   */\n  async sample(logits: Tensor): Promise<[bigint, number][]> {\n    // NOTE: no need to do log_softmax here since we only take the maximum\n    const argmax = max(logits.data as TypedArray)[1];\n\n    // Note: score is meaningless in this context, since we are performing\n    // greedy search (p = 1 => log(p) = 0)\n    return [[BigInt(argmax), 0]];\n  }\n}\n\n/**\n * Class representing a MultinomialSampler.\n */\nclass MultinomialSampler extends LogitsSampler {\n  /**\n   * Sample from the logits.\n   * @param {Tensor} logits\n   * @returns {Promise<[bigint, number][]>}\n   */\n  async sample(logits: Tensor): Promise<[bigint, number][]> {\n    let k = logits.dims.at(-1); // defaults to vocab size\n    if (this.generation_config.top_k > 0) {\n      k = Math.min(this.generation_config.top_k, k);\n    }\n\n    // Get top k tokens\n    const [v, i] = await topk(logits, k);\n\n    // Compute softmax over logits\n    const probabilities = softmax(/** @type {Float32Array} */ v.data);\n\n    return Array.from({ length: this.generation_config.num_beams }, () => {\n      const sampledIndex = this.randomSelect(probabilities as Float32Array);\n      return [\n        i.data[sampledIndex], // token id\n        Math.log(probabilities[sampledIndex]), // score\n      ];\n    });\n  }\n}\n\n/**\n * Class representing a BeamSearchSampler.\n */\nclass BeamSearchSampler extends LogitsSampler {\n  /**\n   * Sample from the logits.\n   * @param {Tensor} logits\n   * @returns {Promise<[bigint, number][]>}\n   */\n  async sample(logits: Tensor): Promise<[bigint, number][]> {\n    let k = logits.dims.at(-1); // defaults to vocab size\n    if (this.generation_config.top_k > 0) {\n      k = Math.min(this.generation_config.top_k, k);\n    }\n\n    // Get top k tokens\n    const [v, i] = await topk(logits, k);\n\n    // Compute softmax over logits\n    const probabilities = softmax(/** @type {Float32Array} */ v.data);\n\n    return Array.from({ length: this.generation_config.num_beams }, (_, x) => {\n      return [\n        i.data[x], // token id\n        Math.log(probabilities[x]), // score\n      ];\n    });\n  }\n}\n","import { GenerationConfig } from '../../generation/configuration_utils.js';\nimport { GenerationFunctionParameters } from '../../generation/parameters';\nexport class WhisperGenerationConfig extends GenerationConfig {\n  /**\n   * Whether to return the timestamps with the text. This enables the `WhisperTimestampsLogitsProcessor`.\n   * @type {boolean}\n   */\n  return_timestamps = null;\n\n  /**\n   * Whether to return token-level timestamps\n   * with the text. This can be used with or without the `return_timestamps` option. To get word-level\n   * timestamps, use the tokenizer to group the tokens into words.\n   * @type {boolean}\n   */\n  return_token_timestamps = null;\n\n  /**\n   * The number of audio frames available in this chunk. This is only used generating word-level timestamps.\n   * @type {number}\n   */\n  num_frames = null;\n\n  /**\n   * Alignment heads to predict word-level timestamps. This is a list of [layer, head] pairs that\n   * select the cross-attention heads that are highly correlated to word-level timing.\n   * @type {[number, number][]}\n   */\n  alignment_heads = null;\n\n  /**\n   * Task to use for generation, either \"translate\" or \"transcribe\".\n   * @type {string}\n   */\n  task = null;\n\n  /**\n   * Language token to use for generation, can be either in the form of `<|en|>`, `en` or `english`.\n   * You can find all the possible language tokens in the `model.generation_config.lang_to_id` dictionary.\n   * @type {string}\n   */\n  language = null;\n\n  /**\n   * The id of the `\"<|notimestamps|>\"` token.\n   * @type {number}\n   */\n  no_timestamps_token_id = null;\n\n  /**\n   * Rank-1 list of token IDs created by passing text to [`~WhisperProcessor.get_prompt_ids`] that is\n   * provided as a prompt to each chunk. This can be used to provide or \"prompt-engineer\" a context for\n   * transcription, e.g. custom vocabularies or proper nouns to make it more likely to predict those words\n   * correctly. It cannot be used in conjunction with `decoder_start_token_id` as it overwrites this value.\n   * @type {number[]}\n   */\n  prompt_ids = null;\n\n  /**\n   * Whether the model is multilingual or not.\n   * @type {boolean}\n   */\n  is_multilingual = null;\n\n  /**\n   * (Optional) A mapping from language tokens to their corresponding IDs.\n   * Only required if the model is multilingual.\n   * @type {Record<string, number>|null}\n   */\n  lang_to_id = null;\n\n  /**\n   * (Optional) A mapping from task tokens to their corresponding IDs.\n   * @type {Record<string, number>|null}\n   */\n  task_to_id = null;\n\n  /**\n   * Used to set the maximum value of the initial timestamp. This is used to prevent the model from\n   * predicting timestamps that are too far in the future.\n   * @type {number}\n   */\n  max_initial_timestamp_index = 1;\n}\n\n/**\n * @typedef {import('../../generation/parameters.js').GenerationFunctionParameters & {generation_config: WhisperGenerationConfig} & WhisperGenerationConfig} WhisperGenerationFunctionParameters\n */\n\nexport type WhisperGenerationFunctionParameters = GenerationFunctionParameters & {generation_config: WhisperGenerationConfig} & WhisperGenerationConfig;","/**\n * @file Definitions of all models available in Transformers.js.\n *\n * **Example:** Load and run an `AutoModel`.\n *\n * ```javascript\n * import { AutoModel, AutoTokenizer } from '@huggingface/transformers';\n *\n * let tokenizer = await AutoTokenizer.from_pretrained('Xenova/bert-base-uncased');\n * let model = await AutoModel.from_pretrained('Xenova/bert-base-uncased');\n *\n * let inputs = await tokenizer('I love transformers!');\n * let { logits } = await model(inputs);\n * // Tensor {\n * //     data: Float32Array(183132) [-7.117443084716797, -7.107812881469727, -7.092104911804199, ...]\n * //     dims: (3) [1, 6, 30522],\n * //     type: \"float32\",\n * //     size: 183132,\n * // }\n * ```\n *\n * We also provide other `AutoModel`s (listed below), which you can use in the same way as the Python library. For example:\n *\n * **Example:** Load and run an `AutoModelForSeq2SeqLM`.\n * ```javascript\n * import { AutoModelForSeq2SeqLM, AutoTokenizer } from '@huggingface/transformers';\n *\n * let tokenizer = await AutoTokenizer.from_pretrained('Xenova/t5-small');\n * let model = await AutoModelForSeq2SeqLM.from_pretrained('Xenova/t5-small');\n *\n * let { input_ids } = await tokenizer('translate English to German: I love transformers!');\n * let outputs = await model.generate(input_ids);\n * let decoded = tokenizer.decode(outputs[0], { skip_special_tokens: true });\n * // 'Ich liebe Transformatoren!'\n * ```\n *\n * @module models\n */\n\nimport { AutoConfig, getKeyValueShapes, PretrainedConfig, TransformersJSConfig } from './configs';\n\nimport { deviceToExecutionProviders, createInferenceSession, isONNXTensor, isONNXProxy } from './backends/onnx';\nimport {\n  DATA_TYPES,\n  DEFAULT_DEVICE_DTYPE_MAPPING,\n  DEFAULT_DTYPE_SUFFIX_MAPPING,\n  isWebGpuFp16Supported,\n} from './utils/dtypes';\n\nimport { Callable } from './utils/generic';\n\nimport { mergeArrays, pick, ProgressCallback } from './utils/core';\n\nimport { getModelFile, getModelJSON } from './utils/hub';\n\nimport { GITHUB_ISSUE_URL } from './utils/constants';\n\nimport {\n  LogitsProcessorList,\n  ForcedBOSTokenLogitsProcessor,\n  ForcedEOSTokenLogitsProcessor,\n  SuppressTokensAtBeginLogitsProcessor,\n  WhisperTimeStampLogitsProcessor,\n  NoRepeatNGramLogitsProcessor,\n  RepetitionPenaltyLogitsProcessor,\n  NoBadWordsLogitsProcessor,\n  MinLengthLogitsProcessor,\n  MinNewTokensLengthLogitsProcessor,\n  TemperatureLogitsWarper,\n  TopKLogitsWarper,\n  TopPLogitsWarper,\n  ClassifierFreeGuidanceLogitsProcessor,\n  LogitsProcessor,\n} from './generation/logits_process';\n\nimport { GenerationConfig } from './generation/configuration_utils';\n\nimport {\n  cat,\n  mean,\n  zeros,\n  zeros_like,\n  ones,\n  ones_like,\n  full,\n  full_like,\n  stack,\n  std_mean,\n  Tensor,\n} from './utils/tensor';\nimport { RawImage } from './utils/image';\n\nimport { dynamic_time_warping, max, medianFilter } from './utils/maths';\nimport { EosTokenCriteria, MaxLengthCriteria, StoppingCriteriaList } from './generation/stopping_criteria';\nimport { LogitsSampler } from './generation/logits_sampler';\nimport { apis } from './env';\n\nimport { WhisperGenerationConfig, WhisperGenerationFunctionParameters } from './models/whisper/generation_whisper';\nimport { whisper_language_to_code } from './models/whisper/common_whisper';\nimport { GenerationFunctionParameters } from './generation/parameters';\n\n//////////////////////////////////////////////////\n// Model types: used internally\nconst MODEL_TYPES = {\n  EncoderOnly: 0,\n  EncoderDecoder: 1,\n  Seq2Seq: 2,\n  Vision2Seq: 3,\n  DecoderOnly: 4,\n  MaskGeneration: 5,\n  ImageTextToText: 6,\n  Musicgen: 7,\n  MultiModality: 8,\n  Phi3V: 9,\n};\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Helper functions\n\n// NOTE: These will be populated fully later\nconst MODEL_TYPE_MAPPING = new Map();\nconst MODEL_NAME_TO_CLASS_MAPPING = new Map();\nconst MODEL_CLASS_TO_NAME_MAPPING = new Map();\n\n/**\n * Constructs an InferenceSession using a model file located at the specified path.\n * @param {string} pretrained_model_name_or_path The path to the directory containing the model file.\n * @param {string} fileName The name of the model file.\n * @param {import('./utils/hub.js').PretrainedModelOptions} options Additional options for loading the model.\n * @returns {Promise<{buffer: Uint8Array, session_options: Object, session_config: Object}>} A Promise that resolves to the data needed to create an InferenceSession object.\n * @private\n */\nasync function getSession(pretrained_model_name_or_path: string, fileName: string, options: any) {\n  const custom_config = options.config?.['transformers.js_config'] ?? {};\n  let device = options.device ?? custom_config.device;\n  if (device && typeof device !== 'string') {\n    if (device.hasOwnProperty(fileName)) {\n      device = device[fileName];\n    } else {\n      console.warn(`device not specified for \"${fileName}\". Using the default device.`);\n      device = null;\n    }\n  }\n\n  // If the device is not specified, we use the default (supported) execution providers.\n  const selectedDevice =\n    /** @type {import(\"./utils/devices.js\").DeviceType} */ device ?? (apis.IS_NODE_ENV ? 'cpu' : 'wasm');\n  const executionProviders = deviceToExecutionProviders(selectedDevice);\n\n  // If options.dtype is specified, we use it to choose the suffix for the model file.\n  // Otherwise, we use the default dtype for the device.\n  let dtype = options.dtype ?? custom_config.dtype;\n  if (typeof dtype !== 'string') {\n    if (dtype && dtype.hasOwnProperty(fileName)) {\n      dtype = dtype[fileName];\n    } else {\n      dtype =\n        DEFAULT_DEVICE_DTYPE_MAPPING[selectedDevice as keyof typeof DEFAULT_DEVICE_DTYPE_MAPPING] ?? DATA_TYPES.fp32;\n      console.warn(\n        `dtype not specified for \"${fileName}\". Using the default dtype (${dtype}) for this device (${selectedDevice}).`,\n      );\n    }\n  }\n\n  if (dtype === DATA_TYPES.auto) {\n    // Try to choose the auto dtype based on the custom config\n    let config_dtype = custom_config.dtype;\n    if (typeof config_dtype !== 'string') {\n      config_dtype = config_dtype[fileName];\n    }\n\n    if (config_dtype && config_dtype !== DATA_TYPES.auto && DATA_TYPES.hasOwnProperty(config_dtype)) {\n      // Defined by the custom config, and is not \"auto\"\n      dtype = config_dtype;\n    } else {\n      // Choose default dtype based on device, falling back to fp32\n      dtype =\n        DEFAULT_DEVICE_DTYPE_MAPPING[selectedDevice as keyof typeof DEFAULT_DEVICE_DTYPE_MAPPING] ?? DATA_TYPES.fp32;\n    }\n  }\n\n  const selectedDtype = /** @type {import(\"./utils/dtypes.js\").DataType} */ dtype;\n\n  if (!DEFAULT_DTYPE_SUFFIX_MAPPING.hasOwnProperty(selectedDtype)) {\n    throw new Error(`Invalid dtype: ${selectedDtype}. Should be one of: ${Object.keys(DATA_TYPES).join(', ')}`);\n  } else if (selectedDtype === DATA_TYPES.fp16 && selectedDevice === 'webgpu' && !(await isWebGpuFp16Supported())) {\n    throw new Error(`The device (${selectedDevice}) does not support fp16.`);\n  }\n\n  // Only valid for models with a decoder\n  const kv_cache_dtype = custom_config.kv_cache_dtype\n    ? typeof custom_config.kv_cache_dtype === 'string'\n      ? custom_config.kv_cache_dtype\n      : (custom_config.kv_cache_dtype[selectedDtype] ?? 'float32')\n    : undefined;\n\n  if (kv_cache_dtype && !['float32', 'float16'].includes(kv_cache_dtype)) {\n    throw new Error(`Invalid kv_cache_dtype: ${kv_cache_dtype}. Should be one of: float32, float16`);\n  }\n\n  const session_config = {\n    dtype: selectedDtype,\n    kv_cache_dtype,\n  };\n\n  // Construct the model file name\n  const suffix = DEFAULT_DTYPE_SUFFIX_MAPPING[selectedDtype as keyof typeof DEFAULT_DTYPE_SUFFIX_MAPPING];\n  const modelFileName = `${options.subfolder ?? ''}/${fileName}${suffix}.onnx`;\n\n  const session_options = { ...options.session_options };\n\n  // Overwrite `executionProviders` if not specified\n  session_options.executionProviders ??= executionProviders;\n\n  // Overwrite `freeDimensionOverrides` if specified in config and not set in session options\n  const free_dimension_overrides = custom_config.free_dimension_overrides;\n  if (free_dimension_overrides) {\n    session_options.freeDimensionOverrides ??= free_dimension_overrides;\n  } else if (selectedDevice.startsWith('webnn') && !session_options.freeDimensionOverrides) {\n    console.warn(\n      'WebNN does not currently support dynamic shapes and requires `free_dimension_overrides` to be set in config.json as a field within \"transformers.js_config\". ' +\n      'When `free_dimension_overrides` is not set, you may experience significant performance degradation.',\n    );\n  }\n\n  const bufferPromise = getModelFile(pretrained_model_name_or_path, modelFileName, true, options);\n\n  // handle onnx external data files\n  const use_external_data_format = options.use_external_data_format ?? custom_config.use_external_data_format;\n  /** @type {Promise<{path: string, data: Uint8Array}>[]} */\n  let externalDataPromises = [];\n  if (\n    use_external_data_format &&\n    (use_external_data_format === true ||\n      (typeof use_external_data_format === 'object' &&\n        use_external_data_format.hasOwnProperty(fileName) &&\n        use_external_data_format[fileName] === true))\n  ) {\n    if (apis.IS_NODE_ENV) {\n      throw new Error('External data format is not yet supported in Node.js');\n    }\n    const path = `${fileName}${suffix}.onnx_data`;\n    const fullPath = `${options.subfolder ?? ''}/${path}`;\n    externalDataPromises.push(\n      new Promise(async (resolve, reject) => {\n        const data = await getModelFile(pretrained_model_name_or_path, fullPath, true, options);\n        resolve({ path, data });\n      }),\n    );\n  } else if (session_options.externalData !== undefined) {\n    externalDataPromises = session_options.externalData.map(async (ext: any) => {\n      if (typeof ext.data === 'string') {\n        const ext_buffer = await getModelFile(pretrained_model_name_or_path, ext.data, true, options);\n        return { ...ext, data: ext_buffer };\n      }\n      return ext;\n    });\n  }\n\n  if (externalDataPromises.length > 0) {\n    session_options.externalData = await Promise.all(externalDataPromises);\n  }\n\n  if (selectedDevice === 'webgpu') {\n    const shapes = getKeyValueShapes(options.config, {\n      prefix: 'present',\n    });\n    if (Object.keys(shapes).length > 0 && !isONNXProxy()) {\n      // Only set preferredOutputLocation if shapes are present and we aren't proxying ONNX\n      /** @type {Record<string, import('onnxruntime-common').Tensor.DataLocation>} */\n      const preferredOutputLocation: Record<string, any> = {};\n      for (const key in shapes) {\n        preferredOutputLocation[key] = 'gpu-buffer';\n      }\n      session_options.preferredOutputLocation = preferredOutputLocation;\n    }\n  }\n\n  const buffer = (await bufferPromise) as Uint8Array;\n\n  return { buffer, session_options, session_config };\n}\n\n/**\n * Helper function to create multiple InferenceSession objects.\n *\n * @param {string} pretrained_model_name_or_path The path to the directory containing the model file.\n * @param {Record<string, string>} names The names of the model files to load.\n * @param {import('./utils/hub.js').PretrainedModelOptions} options Additional options for loading the model.\n * @returns {Promise<Record<string, any>>} A Promise that resolves to a dictionary of InferenceSession objects.\n * @private\n */\nasync function constructSessions(pretrained_model_name_or_path: string, names: Record<string, string>, options: any) {\n  return Object.fromEntries(\n    await Promise.all(\n      Object.keys(names).map(async (name) => {\n        const { buffer, session_options, session_config } = await getSession(\n          pretrained_model_name_or_path,\n          names[name],\n          options,\n        );\n        const session = await createInferenceSession(buffer, session_options, session_config);\n        return [name, session];\n      }),\n    ),\n  );\n}\n\n/**\n * Helper function to load multiple optional configuration files\n * @param {string} pretrained_model_name_or_path The path to the directory containing the config file.\n * @param {Record<string, string>} names The names of the config files to load.\n * @param {import('./utils/hub.js').PretrainedModelOptions} options Additional options for loading the configs.\n * @returns {Promise<Record<string, any>>} A Promise that resolves to a dictionary of configuration objects.\n * @private\n */\nasync function getOptionalConfigs(pretrained_model_name_or_path: string, names: Record<string, string>, options: any) {\n  return Object.fromEntries(\n    await Promise.all(\n      Object.keys(names).map(async (name) => {\n        const config = await getModelJSON(pretrained_model_name_or_path, names[name], false, options);\n        return [name, config];\n      }),\n    ),\n  );\n}\n\n/**\n * Validate model inputs\n * @param {Object} session The InferenceSession object that will be run.\n * @param {Object} inputs The inputs to check.\n * @returns {Record<string, Tensor>} The checked inputs.\n * @throws {Error} If any inputs are missing.\n * @private\n */\nfunction validateInputs(session: any, inputs: any) {\n  /**\n   * NOTE: Create either a shallow or deep copy based on `onnx.wasm.proxy`\n   * @type {Record<string, Tensor>}\n   */\n  const checkedInputs = Object.create(null);\n  const missingInputs = [];\n  for (const inputName of session.inputNames) {\n    const tensor = inputs[inputName];\n    // Rare case where one of the model's input names corresponds to a built-in\n    // object name (e.g., toString), which would cause a simple (!tensor) check to fail,\n    // because it's not undefined but a function.\n    if (!(tensor instanceof Tensor)) {\n      missingInputs.push(inputName);\n      continue;\n    }\n    // NOTE: When `env.wasm.proxy is true` the tensor is moved across the Worker\n    // boundary, transferring ownership to the worker and invalidating the tensor.\n    // So, in this case, we simply sacrifice a clone for it.\n    checkedInputs[inputName] = isONNXProxy() ? tensor.clone() : tensor;\n  }\n  if (missingInputs.length > 0) {\n    throw new Error(\n      `An error occurred during model execution: \"Missing the following inputs: ${missingInputs.join(', ')}.`,\n    );\n  }\n\n  const numInputsProvided = Object.keys(inputs).length;\n  const numInputsNeeded = session.inputNames.length;\n  if (numInputsProvided > numInputsNeeded) {\n    // No missing inputs, but too many inputs were provided.\n    // Warn the user and ignore the extra inputs.\n    let ignored = Object.keys(inputs).filter((inputName) => !session.inputNames.includes(inputName));\n    console.warn(\n      `WARNING: Too many inputs were provided (${numInputsProvided} > ${numInputsNeeded}). The following inputs will be ignored: \"${ignored.join(', ')}\".`,\n    );\n  }\n\n  return checkedInputs;\n}\n\n/**\n * Executes an InferenceSession using the specified inputs.\n * NOTE: `inputs` must contain at least the input names of the model.\n *  - If additional inputs are passed, they will be ignored.\n *  - If inputs are missing, an error will be thrown.\n *\n * @param {Object} session The InferenceSession object to run.\n * @param {Object} inputs An object that maps input names to input tensors.\n * @returns {Promise<Object>} A Promise that resolves to an object that maps output names to output tensors.\n * @private\n */\nasync function sessionRun(session: any, inputs: any) {\n  console.log(`Running session ${session.path || 'unknown'}:`, {\n    inputNames: session.inputNames,\n    inputShapes: Object.fromEntries(\n      Object.entries(inputs).map(([k, v]) => [k, (v as any).dims])\n    )\n  });\n  const checkedInputs = validateInputs(session, inputs);\n  try {\n    // pass the original ort tensor\n    const ortFeed = Object.fromEntries(\n      Object.entries(checkedInputs).map(([k, v]) => [k, (v as Tensor).ort_tensor]),\n    );\n    let output = await session.run(ortFeed);\n    console.log('Session run successful:', {\n      outputNames: Object.keys(output)\n    });\n    output = replaceTensors(output);\n    return output;\n  } catch (e) {\n    // Error messages can be long (nested) and uninformative. For this reason,\n    // we apply minor formatting to show the most important information\n    const formatted = Object.fromEntries(\n      Object.entries(checkedInputs).map(([k, v]) => [\n        k,\n        {\n          // Extract these properties from the underlying ORT tensor\n          type: (v as Tensor).type,\n          dims: (v as Tensor).dims,\n          data: (v as Tensor).data,\n        },\n      ]),\n    );\n\n    console.error('Session run failed:', {\n      e,\n      session: session.path,\n      inputNames: session.inputNames,\n      inputShapes: Object.fromEntries(\n        Object.entries(inputs).map(([k, v]) => [k, (v as any).dims])\n      )\n    });\n\n    // This usually occurs when the inputs are of the wrong type.\n    console.error(`An error occurred during model execution: \"${e}\".`);\n    console.error('Inputs given to model:', formatted);\n    throw e;\n  }\n}\n\n/**\n * Replaces ONNX Tensor objects with custom Tensor objects to support additional functions.\n * @param {Object} obj The object to replace tensor objects in.\n * @returns {Object} The object with tensor objects replaced by custom Tensor objects.\n * @private\n */\nfunction replaceTensors(obj: any) {\n  for (let prop in obj) {\n    if (isONNXTensor(obj[prop])) {\n      obj[prop] = new Tensor(obj[prop]);\n    } else if (typeof obj[prop] === 'object') {\n      replaceTensors(obj[prop]);\n    }\n  }\n  return obj;\n}\n\n/**\n * Converts an array or Tensor of integers to an int64 Tensor.\n * @param {any[]|Tensor} items The input integers to be converted.\n * @returns {Tensor} The int64 Tensor with the converted values.\n * @throws {Error} If the input array is empty or the input is a batched Tensor and not all sequences have the same length.\n * @private\n */\nfunction toI64Tensor(items: any) {\n  if (items instanceof Tensor) {\n    return items;\n  }\n  // items is an array\n  if (items.length === 0) {\n    throw Error('items must be non-empty');\n  }\n\n  if (Array.isArray(items[0])) {\n    // batched\n    if (items.some((x: any) => x.length !== items[0].length)) {\n      throw Error(\n        \"Unable to create tensor, you should probably activate truncation and/or padding with 'padding=True' and/or 'truncation=True' to have batched tensors with the same length.\",\n      );\n    }\n\n    return new Tensor('int64', BigInt64Array.from(items.flat().map((x: any) => BigInt(x))), [\n      items.length,\n      items[0].length,\n    ]);\n  } else {\n    //flat\n    return new Tensor('int64', BigInt64Array.from(items.map((x: any) => BigInt(x))), [1, items.length]);\n  }\n}\n\n/**\n * Creates a boolean tensor with a single value.\n * @param {boolean} value The value of the tensor.\n * @returns {Tensor} The boolean tensor.\n * @private\n */\nfunction boolTensor(value: boolean) {\n  return new Tensor('bool', [value], [1]);\n}\n\n// JS doesn't support mixins, so we define some reused functions here, and allow \"this\" to be passed in\n/**\n * Perform forward pass on the seq2seq model (both encoder and decoder).\n * @param {Object} self The seq2seq model object.\n * @param {Object} model_inputs The input object for the model containing encoder and decoder inputs.\n * @returns {Promise<Seq2SeqLMOutput>} Promise that resolves with the output of the seq2seq model.\n * @private\n */\nasync function seq2seqForward(self: any, model_inputs: any) {\n  let { encoder_outputs, input_ids, decoder_input_ids, ...other_decoder_inputs } = model_inputs;\n  // Encode if needed\n  if (!encoder_outputs) {\n    const encoder_inputs = pick(model_inputs, self.sessions['model'].inputNames);\n    // Encoder outputs are not given, so we must compute them.\n    encoder_outputs = (await encoderForward(self, encoder_inputs)).last_hidden_state;\n  }\n\n  other_decoder_inputs.input_ids = decoder_input_ids;\n  other_decoder_inputs.encoder_hidden_states = encoder_outputs;\n\n  if (self.sessions['decoder_model_merged'].inputNames.includes('encoder_attention_mask')) {\n    other_decoder_inputs.encoder_attention_mask = model_inputs.attention_mask;\n  }\n\n  const decoderResults = await decoderForward(self, other_decoder_inputs, true);\n\n  return decoderResults;\n}\n\n/**\n * Forward pass of an encoder model.\n * @param {Object} self The encoder model.\n * @param {Object} model_inputs The input data to be used for the forward pass.\n * @returns {Promise<Object>} The model's outputs.\n * @private\n */\nasync function encoderForward(self: any, model_inputs: any) {\n  const session = self.sessions['model'];\n  const encoderFeeds = pick(model_inputs, session.inputNames);\n  if (session.inputNames.includes('inputs_embeds') && !encoderFeeds.inputs_embeds) {\n    if (!model_inputs.input_ids) {\n      throw new Error('Both `input_ids` and `inputs_embeds` are missing in the model inputs.');\n    }\n    encoderFeeds.inputs_embeds = await self.encode_text({ input_ids: model_inputs.input_ids });\n  }\n  if (session.inputNames.includes('token_type_ids') && !encoderFeeds.token_type_ids) {\n    // Assign default `token_type_ids` (all zeroes) to the `encoderFeeds` if the model expects it,\n    // but they weren't created by the tokenizer.\n    // encoderFeeds.token_type_ids = new Tensor(\n    //   'int64',\n    //   new BigInt64Array(encoderFeeds.input_ids.data.length),\n    //   encoderFeeds.input_ids.dims,\n    // );\n\n    if (!encoderFeeds.input_ids) {\n      throw new Error('Both `input_ids` and `token_type_ids` are missing in the model inputs.');\n    }\n    // Assign default `token_type_ids` (all zeroes) to the `encoderFeeds` if the model expects it,\n    // but they weren't created by the tokenizer.\n    encoderFeeds.token_type_ids = zeros_like(encoderFeeds.input_ids);\n  }\n\n  if (session.inputNames.includes('pixel_mask') && !encoderFeeds.pixel_mask) {\n    if (!encoderFeeds.pixel_values) {\n      throw new Error('Both `pixel_values` and `pixel_mask` are missing in the model inputs.');\n    }\n    // Assign default `pixel_mask` (all ones) to the `encoderFeeds` if the model expects it,\n    // but they weren't created by the processor.\n    const dims = encoderFeeds.pixel_values.dims;\n    encoderFeeds.pixel_mask = ones([dims[0], dims[2], dims[3]]);\n  }\n  // console.log(\"encoder forward running here: \", session, encoderFeeds)\n  return await sessionRun(session, encoderFeeds);\n}\n\n/**\n * Forward pass of a decoder model.\n * @param {Object} self The decoder model.\n * @param {Object} model_inputs The input data to be used for the forward pass.\n * @returns {Promise<Object>} The logits and past key values.\n * @private\n */\nasync function decoderForward(self: any, model_inputs: any, is_encoder_decoder = false) {\n  const session = self.sessions[is_encoder_decoder ? 'decoder_model_merged' : 'model'];\n\n  // Add debugging\n  console.log('Decoder inputs:', model_inputs);\n  console.log('Session config:', session.config);\n\n  const { past_key_values, ...new_model_inputs } = model_inputs;\n\n  if (session.inputNames.includes('use_cache_branch')) {\n    new_model_inputs.use_cache_branch = boolTensor(!!past_key_values);\n  }\n  if (\n    session.inputNames.includes('position_ids') &&\n    new_model_inputs.attention_mask &&\n    !new_model_inputs.position_ids\n  ) {\n    // NOTE: Handle a special case for paligemma models, where positions are 1-indexed\n    const start_index = self.config?.model_type === 'paligemma' ? 1 : 0;\n    new_model_inputs.position_ids = createPositionIds(new_model_inputs, past_key_values, start_index);\n  }\n\n  // Unpack the `past_key_values` object into model inputs\n  self.addPastKeyValues(new_model_inputs, past_key_values);\n\n  // Select only the inputs that are needed for the current session\n  const fixed = pick(new_model_inputs, session.inputNames);\n  return await sessionRun(session, fixed);\n}\n\nfunction default_merge_input_ids_with_image_features({\n  image_token_id,\n  inputs_embeds,\n  image_features,\n  input_ids,\n  attention_mask,\n}: {\n  image_token_id: number;\n  inputs_embeds: Tensor;\n  image_features: Tensor;\n  input_ids: Tensor;\n  attention_mask: Tensor;\n}) {\n  const image_tokens = input_ids.tolist().map((ids: any) =>\n    ids.reduce((acc: any, x: any, idx: any) => {\n      if (x == image_token_id) acc.push(idx);\n      return acc;\n    }, []),\n  );\n  const n_image_tokens = image_tokens.reduce((acc: any, x: any) => acc + x.length, 0);\n  const n_image_features = image_features.dims[0];\n  if (n_image_tokens !== n_image_features) {\n    throw new Error(\n      `Image features and image tokens do not match: tokens: ${n_image_tokens}, features ${n_image_features}`,\n    );\n  }\n\n  // Equivalent to performing a masked_scatter\n  let img = 0;\n  for (let i = 0; i < image_tokens.length; ++i) {\n    const tokens = image_tokens[i];\n    const embeds = inputs_embeds[i];\n    for (let j = 0; j < tokens.length; ++j) {\n      (embeds[tokens[j]].data as any).set(image_features[img++].data);\n    }\n  }\n  return { inputs_embeds, attention_mask };\n}\n\n/**\n * Forward pass of an image-text-to-text model.\n * @param {Object} self The image-text-to-text model model.\n * @param {Object} model_inputs The input data to be used for the forward pass.\n * @param {Tensor} [model_inputs.input_ids=null]\n * @param {Tensor} [model_inputs.attention_mask=null]\n * @param {Tensor} [model_inputs.pixel_values=null]\n * @param {Tensor} [model_inputs.position_ids=null]\n * @param {Tensor} [model_inputs.inputs_embeds=null]\n * @param {Tensor} [model_inputs.past_key_values=null]\n * @param {Object} [model_inputs.generation_config=null]\n * @param {Object} [model_inputs.logits_processor=null]\n * @returns {Promise<Tensor>} The model's output tensor\n * @private\n */\nasync function imageTextToTextForward(\n  self: any,\n  {\n    // Produced by the tokenizer/processor:\n    input_ids = null,\n    attention_mask = null,\n    pixel_values = null,\n\n    // Used during generation:\n    position_ids = null,\n    inputs_embeds = null,\n    past_key_values = null,\n\n    // Generic generation parameters\n    generation_config = null,\n    logits_processor = null,\n\n    // TODO: needed?\n    ...kwargs\n  },\n) {\n  if (!inputs_embeds) {\n    // 1. Extract the input embeddings\n    inputs_embeds = await self.encode_text({ input_ids, ...kwargs });\n\n    // 2. Possibly, merge text and images\n    if (pixel_values && (input_ids as any)?.dims[1] !== 1) {\n      const image_features = await self.encode_image({ pixel_values, ...kwargs });\n\n      ({ inputs_embeds, attention_mask } = self._merge_input_ids_with_image_features({\n        image_features,\n        inputs_embeds,\n        input_ids,\n        attention_mask,\n      }));\n    } else if (past_key_values && pixel_values && (input_ids as any)?.dims[1] === 1) {\n      // This is the case when we are generating with cache\n      const target_length = (input_ids as any)?.dims[1] ?? 1; // always 1\n      const past_length = (Object.values(past_key_values)[0] as any).dims.at(-2);\n\n      attention_mask = cat(\n        [\n          ones([(input_ids as any).dims[0], past_length]),\n          (attention_mask as any)?.slice(null, [(attention_mask as any).dims[1] - target_length, (attention_mask as any).dims[1]]),\n        ],\n        1,\n      ) as any;\n    }\n  }\n\n  if (!position_ids) {\n    if (self.config.model_type === 'qwen2_vl') {\n      // Special case for qwen2_vl models\n      // @ts-ignore\n      const { image_grid_thw, video_grid_thw } = kwargs;\n      [position_ids] = self.get_rope_index(input_ids, image_grid_thw, video_grid_thw, attention_mask);\n    }\n  }\n\n  const outputs = await decoderForward(\n    self,\n    {\n      inputs_embeds,\n      past_key_values,\n      attention_mask,\n      position_ids,\n      generation_config,\n      logits_processor,\n    },\n    true,\n  );\n  return outputs;\n}\n\n/**\n * Helper function to perform the following:\n * ```python\n * x = attention_mask.long().cumsum(-1) - 1\n * x.masked_fill_(attention_mask == 0, 1)\n * ```\n * @param {Tensor} attention_mask\n * @returns {{data: BigInt64Array, dims: number[]}}\n */\nfunction cumsum_masked_fill(attention_mask: Tensor, start_index = 0) {\n  const [bz, seq_len] = attention_mask.dims;\n  const attn_mask_data = attention_mask.data;\n\n  const data = new BigInt64Array(attn_mask_data.length);\n  for (let i = 0; i < bz; ++i) {\n    const start = i * seq_len;\n    let sum = BigInt(start_index);\n    for (let j = 0; j < seq_len; ++j) {\n      const index = start + j;\n      if (attn_mask_data[index] === 0n) {\n        data[index] = BigInt(1);\n      } else {\n        // === 1n\n        data[index] = sum;\n        sum += attn_mask_data[index];\n      }\n    }\n  }\n  return { data, dims: attention_mask.dims };\n}\n\n/**\n * If the model supports providing position_ids, we create position_ids on the fly for batch generation,\n * by computing the cumulative sum of the attention mask along the sequence length dimension.\n *\n * Equivalent to:\n * ```python\n * position_ids = attention_mask.long().cumsum(-1) - 1\n * position_ids.masked_fill_(attention_mask == 0, 1)\n * if past_key_values:\n *     position_ids = position_ids[:, -input_ids.shape[1] :]\n * ```\n */\nfunction createPositionIds(model_inputs: Record<string, any>, past_key_values = null, start_index = 0) {\n  const { input_ids, inputs_embeds, attention_mask } = model_inputs;\n\n  const { data, dims } = cumsum_masked_fill(attention_mask, start_index);\n  let position_ids = new Tensor('int64', data, dims);\n  if (past_key_values) {\n    const offset = -(input_ids ?? inputs_embeds).dims.at(1);\n    // position_ids = position_ids.slice(null, [offset, null]);\n    position_ids = position_ids.slice(null, [offset]);\n  }\n  return position_ids;\n}\n\nfunction decoder_prepare_inputs_for_generation(\n  self: PreTrainedModel,\n  input_ids: Tensor,\n  model_inputs: Record<string, any>,\n  generation_config: GenerationConfig,\n) {\n  if (model_inputs.past_key_values) {\n    const past_length = (Object.values(model_inputs.past_key_values)[0] as any).dims.at(-2);\n    const { input_ids, attention_mask } = model_inputs;\n\n    // Keep only the unprocessed tokens:\n    // 1 - If the length of the attention_mask exceeds the length of input_ids, then we are in a setting where\n    // some of the inputs are exclusively passed as part of the cache (e.g. when passing input_embeds as\n    // input)\n    if (attention_mask && attention_mask.dims[1] > input_ids.dims[1]) {\n      // NOTE: not needed since we only pass the generated tokens to the next forward pass\n      // const offset = -(attention_mask.dims[1] - past_length);\n      // model_inputs.input_ids = input_ids.slice(null, [offset, null]);\n    }\n    // 2 - If the past_length is smaller than input_ids', then input_ids holds all input tokens.\n    // We can discard input_ids based on the past_length.\n    else if (past_length < input_ids.dims[1]) {\n      // NOTE: Required for phi models.\n      // See https://github.com/huggingface/transformers/issues/30809#issuecomment-2111918479 for more information.\n      model_inputs.input_ids = input_ids.slice(null, [past_length, null]);\n    }\n    // 3 - Otherwise (past_length >= input_ids.shape[1]), let's assume input_ids only has unprocessed tokens.\n    else {\n      if (\n        // NOTE: Only used by VLMs (!= so that null matches undefined)\n        (self.config as any).image_token_index != null &&\n        // Equivalent to `self.config.image_token_index in input_ids` (== so that int matches bigint)\n        input_ids.data.some((x: any) => x == (self.config as any).image_token_index)\n      ) {\n        // TODO: Support multiple image tokens\n        const num_image_tokens = (self.config as any).num_image_tokens;\n        if (!num_image_tokens) {\n          throw new Error('`num_image_tokens` is missing in the model configuration.');\n        }\n\n        const num_new_tokens = input_ids.dims[1] - (past_length - num_image_tokens);\n        model_inputs.input_ids = input_ids.slice(null, [-num_new_tokens, null]);\n\n        // TODO: The attention mask should be formed from the attention mask passed in model_inputs\n        model_inputs.attention_mask = ones([1, past_length + num_new_tokens]);\n      }\n    }\n  }\n\n  return model_inputs;\n}\n\nfunction encoder_decoder_prepare_inputs_for_generation(\n  self: PreTrainedModel,\n  input_ids: Tensor,\n  model_inputs: Record<string, any>,\n  generation_config: GenerationConfig,\n) {\n  if (model_inputs.past_key_values) {\n    input_ids = input_ids.map((x: any) => [x.at(-1)]);\n  }\n\n  return {\n    ...model_inputs,\n    decoder_input_ids: toI64Tensor(input_ids),\n  };\n}\n\nfunction image_text_to_text_prepare_inputs_for_generation(\n  self: PreTrainedModel,\n  ...args: [Tensor, Record<string, any>, GenerationConfig]\n) {\n  if (self.config.is_encoder_decoder) {\n    return encoder_decoder_prepare_inputs_for_generation(self, ...args);\n  } else {\n    return decoder_prepare_inputs_for_generation(self, ...args);\n  }\n}\n\nfunction multimodality_prepare_inputs_for_generation(\n  self: PreTrainedModel,\n  input_ids: Tensor,\n  model_inputs: Record<string, any>,\n  generation_config: GenerationConfig,\n) {\n  const has_past_key_values = !!model_inputs.past_key_values;\n\n  if (generation_config.guidance_scale !== null && generation_config.guidance_scale > 1) {\n    if (has_past_key_values) {\n      model_inputs.input_ids = cat([model_inputs.input_ids, model_inputs.input_ids], 0);\n      // NOTE: attention_mask handled in generation\n    } else {\n      model_inputs.input_ids = cat(\n        [model_inputs.input_ids, full_like(model_inputs.input_ids, BigInt(generation_config.pad_token_id as number))],\n        0,\n      );\n      model_inputs.attention_mask = cat([model_inputs.attention_mask, full_like(model_inputs.attention_mask, 0n)], 0);\n    }\n  }\n\n  if (has_past_key_values || !model_inputs.pixel_values) {\n    model_inputs.pixel_values = full([0, 0, 3, 384, 384], 1.0);\n  }\n\n  if (has_past_key_values) {\n    const num_img_tokens = 0;\n    const num_text_tokens = 1;\n    const has_image = num_img_tokens > 0 ? 1 : 0;\n\n    const batch_size = 1;\n    model_inputs.images_seq_mask = new Tensor(\n      'bool',\n      new Array(num_img_tokens + num_text_tokens).fill(true).fill(false, 0, num_text_tokens),\n      [batch_size, num_img_tokens + num_text_tokens],\n    );\n    model_inputs.images_emb_mask = new Tensor('bool', new Array(num_img_tokens).fill(!!has_image), [\n      batch_size,\n      1,\n      num_img_tokens,\n    ]);\n  }\n  return model_inputs;\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n/**\n * A base class for pre-trained models that provides the model configuration and an ONNX session.\n */\nexport class PreTrainedModel extends Callable {\n  main_input_name = 'input_ids';\n  forward_params = ['input_ids', 'attention_mask'];\n  /**\n   * Creates a new instance of the `PreTrainedModel` class.\n   * @param {import('./configs.js').PretrainedConfig} config The model configuration.\n   * @param {Record<string, any>} sessions The inference sessions for the model.\n   * @param {Record<string, Object>} configs Additional configuration files (e.g., generation_config.json).\n   */\n  config: PretrainedConfig;\n  sessions: Record<string, any>;\n  configs: Record<string, any>;\n  can_generate: boolean;\n  _forward: (self: PreTrainedModel, model_inputs: Record<string, any>) => Promise<any>;\n  _prepare_inputs_for_generation: (\n    self: PreTrainedModel,\n    input_ids: Tensor,\n    model_inputs: Record<string, any>,\n    generation_config: GenerationConfig,\n    ...args: any[]\n  ) => Record<string, any>;\n  custom_config: TransformersJSConfig;\n  constructor(config: PretrainedConfig, sessions: Record<string, any>, configs: Record<string, any>) {\n    super();\n\n    this.config = config;\n    this.sessions = sessions;\n    this.configs = configs;\n\n    const modelName = MODEL_CLASS_TO_NAME_MAPPING.get(this.constructor);\n    const modelType = MODEL_TYPE_MAPPING.get(modelName);\n\n    this.can_generate = false;\n    this._forward = PreTrainedModel.prototype._forward;\n\n    this._prepare_inputs_for_generation = PreTrainedModel.prototype._prepare_inputs_for_generation;\n    switch (modelType) {\n      case MODEL_TYPES.DecoderOnly:\n        this.can_generate = true;\n        this._forward = decoderForward;\n        this._prepare_inputs_for_generation = decoder_prepare_inputs_for_generation;\n        break;\n      case MODEL_TYPES.Seq2Seq:\n      case MODEL_TYPES.Vision2Seq:\n      case MODEL_TYPES.Musicgen:\n        this.can_generate = true;\n\n        this._forward = seq2seqForward;\n        this._prepare_inputs_for_generation = encoder_decoder_prepare_inputs_for_generation;\n        break;\n\n      case MODEL_TYPES.EncoderDecoder:\n        this._forward = seq2seqForward;\n        break;\n      case MODEL_TYPES.ImageTextToText:\n        this.can_generate = true;\n        this._forward = imageTextToTextForward;\n        this._prepare_inputs_for_generation = image_text_to_text_prepare_inputs_for_generation;\n        break;\n      case MODEL_TYPES.Phi3V:\n        this.can_generate = true;\n        this._prepare_inputs_for_generation = image_text_to_text_prepare_inputs_for_generation;\n        break;\n\n      case MODEL_TYPES.MultiModality:\n        this.can_generate = true;\n        this._prepare_inputs_for_generation = multimodality_prepare_inputs_for_generation;\n        break;\n\n      default:\n        // should be MODEL_TYPES.EncoderOnly\n        this._forward = encoderForward;\n        break;\n    }\n\n    if (this.can_generate) {\n      this.forward_params.push('past_key_values');\n    }\n\n    /** @type {import('./configs.js').TransformersJSConfig} */\n    this.custom_config = this.config['transformers_js_config'] ?? {};\n  }\n\n  /**\n   * Disposes of all the ONNX sessions that were created during inference.\n   * @returns {Promise<unknown[]>} An array of promises, one for each ONNX session that is being disposed.\n   * @todo Use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry\n   */\n  async dispose() {\n    const promises = [];\n    for (const session of Object.values(this.sessions)) {\n      if (session?.handler?.dispose) {\n        promises.push(session.handler.dispose());\n      }\n    }\n    return await Promise.all(promises);\n  }\n\n  /**\n   * Instantiate one of the model classes of the library from a pretrained model.\n   *\n   * The model class to instantiate is selected based on the `model_type` property of the config object\n   * (either passed as an argument or loaded from `pretrained_model_name_or_path` if possible)\n   *\n   * @param {string} pretrained_model_name_or_path The name or path of the pretrained model. Can be either:\n   * - A string, the *model id* of a pretrained model hosted inside a model repo on huggingface.co.\n   *   Valid model ids can be located at the root-level, like `bert-base-uncased`, or namespaced under a\n   *   user or organization name, like `dbmdz/bert-base-german-cased`.\n   * - A path to a *directory* containing model weights, e.g., `./my_model_directory/`.\n   * @param {import('./utils/hub.js').PretrainedModelOptions} options Additional options for loading the model.\n   *\n   * @returns {Promise<PreTrainedModel>} A new instance of the `PreTrainedModel` class.\n   */\n  static async from_pretrained(\n    pretrained_model_name_or_path: string,\n    {\n      progress_callback = null,\n      config = null,\n      cache_dir = null,\n      local_files_only = false,\n      revision = 'main',\n      model_file_name = null,\n      subfolder = 'onnx',\n      device = null,\n      dtype = null,\n      use_external_data_format = null,\n      session_options = {},\n    }: ModelOptions = {},\n  ) {\n    let options = {\n      progress_callback,\n      config,\n      cache_dir,\n      local_files_only,\n      revision,\n      model_file_name,\n      subfolder,\n      device,\n      dtype,\n      use_external_data_format,\n      session_options,\n    };\n\n    const modelName = MODEL_CLASS_TO_NAME_MAPPING.get(this);\n    const modelType = MODEL_TYPE_MAPPING.get(modelName);\n\n    config = (options.config as any) = await AutoConfig.from_pretrained(pretrained_model_name_or_path, options);\n\n    let info;\n    if (modelType === MODEL_TYPES.DecoderOnly) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: options.model_file_name ?? 'model',\n          },\n          options,\n        ),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.Seq2Seq || modelType === MODEL_TYPES.Vision2Seq) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: 'encoder_model',\n            decoder_model_merged: 'decoder_model_merged',\n          },\n          options,\n        ),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.MaskGeneration) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: 'vision_encoder',\n            prompt_encoder_mask_decoder: 'prompt_encoder_mask_decoder',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.EncoderDecoder) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: 'encoder_model',\n            decoder_model_merged: 'decoder_model_merged',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.ImageTextToText) {\n      const sessions = {\n        embed_tokens: 'embed_tokens',\n        vision_encoder: 'vision_encoder',\n        decoder_model_merged: 'decoder_model_merged',\n      };\n      if ((config as any).is_encoder_decoder) {\n        (sessions as any)['model'] = 'encoder_model';\n      }\n      info = await Promise.all([\n        constructSessions(pretrained_model_name_or_path, sessions, options),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.Musicgen) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: 'text_encoder',\n            decoder_model_merged: 'decoder_model_merged',\n            encodec_decode: 'encodec_decode',\n          },\n          options,\n        ),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.MultiModality) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            prepare_inputs_embeds: 'prepare_inputs_embeds',\n            model: 'language_model',\n            lm_head: 'lm_head',\n            gen_head: 'gen_head',\n            gen_img_embeds: 'gen_img_embeds',\n            image_decode: 'image_decode',\n          },\n          options,\n        ),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else if (modelType === MODEL_TYPES.Phi3V) {\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            prepare_inputs_embeds: 'prepare_inputs_embeds',\n            model: 'model',\n            vision_encoder: 'vision_encoder',\n          },\n          options,\n        ),\n        getOptionalConfigs(\n          pretrained_model_name_or_path,\n          {\n            generation_config: 'generation_config.json',\n          },\n          options,\n        ),\n      ]);\n    } else {\n      // should be MODEL_TYPES.EncoderOnly\n      if (modelType !== MODEL_TYPES.EncoderOnly) {\n        const type = modelName ?? (config as any)?.model_type;\n        if (type !== 'custom') {\n          console.warn(\n            `Model type for '${type}' not found, assuming encoder-only architecture. Please report this at ${GITHUB_ISSUE_URL}.`,\n          );\n        }\n      }\n      info = await Promise.all([\n        constructSessions(\n          pretrained_model_name_or_path,\n          {\n            model: options.model_file_name ?? 'model',\n          },\n          options,\n        ),\n      ]);\n    }\n\n    // @ts-ignore\n    return new this(config, ...info);\n  }\n\n  /**\n   * Runs the model with the provided inputs\n   * @param {Object} model_inputs Object containing input tensors\n   * @returns {Promise<Object>} Object containing output tensors\n   */\n  async _call(model_inputs: Record<string, unknown>) {\n    return await this.forward(model_inputs);\n  }\n\n  /**\n   * Forward method for a pretrained model. If not overridden by a subclass, the correct forward method\n   * will be chosen based on the model type.\n   * @param {Object} model_inputs The input data to the model in the format specified in the ONNX model.\n   * @returns {Promise<Object>} The output data from the model in the format specified in the ONNX model.\n   * @throws {Error} This method must be implemented in subclasses.\n   */\n  async forward(model_inputs: Record<string, unknown>) {\n    return await this._forward(this, model_inputs);\n  }\n\n  /**\n   * Get the model's generation config, if it exists.\n   * @returns {GenerationConfig|null} The model's generation config if it exists, otherwise `null`.\n   */\n  get generation_config() {\n    return this.configs?.generation_config ?? null;\n  }\n\n  /**\n   * This function returns a [`LogitsProcessorList`] list object that contains all relevant [`LogitsWarper`]\n   * instances used for multinomial sampling.\n   * @param {GenerationConfig} generation_config The generation config.\n   * @returns {LogitsProcessorList} generation_config\n   */\n  _get_logits_warper(generation_config: GenerationConfig) {\n    // instantiate warpers list\n    const warpers = new LogitsProcessorList();\n\n    if (generation_config.temperature !== null && generation_config.temperature !== 1.0) {\n      warpers.push(new TemperatureLogitsWarper(generation_config.temperature));\n    }\n    if (generation_config.top_k !== null && generation_config.top_k !== 0) {\n      // TODO: add min_tokens_to_keep\n      warpers.push(new TopKLogitsWarper(generation_config.top_k) as any);\n    }\n    if (generation_config.top_p !== null && generation_config.top_p < 1.0) {\n      // TODO: add min_tokens_to_keep\n      warpers.push(new TopPLogitsWarper(generation_config.top_p) as any);\n    }\n\n    return warpers;\n  }\n\n  /**\n   * @param {GenerationConfig} generation_config\n   * @param {number} input_ids_seq_length The starting sequence length for the input ids.\n   * @returns {LogitsProcessorList}\n   * @private\n   */\n  _get_logits_processor(\n    generation_config: GenerationConfig,\n    input_ids_seq_length: number,\n    // encoder_input_ids, TODO\n    // prefix_allowed_tokens_fn, TODO\n    logits_processor: LogitsProcessorList | null = null,\n  ) {\n    const processors = new LogitsProcessorList();\n\n    // if (generation_config.diversity_penalty !== null && generation_config.diversity_penalty > 0.0) {\n    //     processors.push(new HammingDiversityLogitsProcessor(\n    //         generation_config.diversity_penalty,\n    //         generation_config.num_beams,\n    //         generation_config.num_beam_groups\n    //     ));\n    // }\n\n    // if (generation_config.encoder_repetition_penalty !== null && generation_config.encoder_repetition_penalty !== 1.0) {\n    //     processors.push(new EncoderRepetitionPenaltyLogitsProcessor(\n    //         generation_config.encoder_repetition_penalty,\n    //         encoder_input_ids\n    //     ));\n    // }\n\n    if (generation_config.repetition_penalty !== null && generation_config.repetition_penalty !== 1.0) {\n      processors.push(new RepetitionPenaltyLogitsProcessor(generation_config.repetition_penalty));\n    }\n\n    if (generation_config.no_repeat_ngram_size !== null && generation_config.no_repeat_ngram_size > 0) {\n      processors.push(new NoRepeatNGramLogitsProcessor(generation_config.no_repeat_ngram_size));\n    }\n\n    // if (generation_config.encoder_no_repeat_ngram_size !== null && generation_config.encoder_no_repeat_ngram_size > 0) {\n    //     if (this.config.is_encoder_decoder) {\n    //         processors.push(new EncoderNoRepeatNGramLogitsProcessor(\n    //             generation_config.encoder_no_repeat_ngram_size,\n    //             encoder_input_ids\n    //         ));\n    //     } else {\n    //         throw new Error(\"It's impossible to use `encoder_no_repeat_ngram_size` with decoder-only architecture\");\n    //     }\n    // }\n\n    if (generation_config.bad_words_ids !== null) {\n      processors.push(\n        new NoBadWordsLogitsProcessor(\n          generation_config.bad_words_ids,\n          (generation_config.eos_token_id as any),\n        ),\n      );\n    }\n\n    if (\n      generation_config.min_length !== null &&\n      generation_config.eos_token_id !== null &&\n      generation_config.min_length > 0\n    ) {\n      processors.push(new MinLengthLogitsProcessor(generation_config.min_length, generation_config.eos_token_id));\n    }\n\n    if (\n      generation_config.min_new_tokens !== null &&\n      generation_config.eos_token_id !== null &&\n      generation_config.min_new_tokens > 0\n    ) {\n      processors.push(\n        new MinNewTokensLengthLogitsProcessor(\n          input_ids_seq_length,\n          generation_config.min_new_tokens,\n          generation_config.eos_token_id,\n        ),\n      );\n    }\n\n    // if (prefix_allowed_tokens_fn !== null) {\n    //     processors.push(new PrefixConstrainedLogitsProcessor(\n    //         prefix_allowed_tokens_fn,\n    //         generation_config.num_beams / generation_config.num_beam_groups\n    //     ));\n    // }\n\n    if (generation_config.forced_bos_token_id !== null) {\n      processors.push(new ForcedBOSTokenLogitsProcessor(generation_config.forced_bos_token_id));\n    }\n\n    if (generation_config.forced_eos_token_id !== null) {\n      processors.push(\n        new ForcedEOSTokenLogitsProcessor(generation_config.max_length, generation_config.forced_eos_token_id),\n      );\n    }\n\n    // if (generation_config.remove_invalid_values === true) {\n    //     processors.push(new InfNanRemoveLogitsProcessor());\n    // }\n\n    // if (generation_config.exponential_decay_length_penalty !== null) {\n    //     processors.push(new ExponentialDecayLengthPenalty(\n    //         generation_config.exponential_decay_length_penalty,\n    //         generation_config.eos_token_id,\n    //         input_ids_seq_length\n    //     ));\n    // }\n\n    // if (generation_config.suppress_tokens !== null) {\n    //     processors.push(new SuppressTokensLogitsProcessor(generation_config.suppress_tokens));\n    // }\n\n    if (generation_config.begin_suppress_tokens !== null) {\n      const begin_index =\n        input_ids_seq_length > 1 || generation_config.forced_bos_token_id === null\n          ? input_ids_seq_length\n          : input_ids_seq_length + 1;\n\n      processors.push(new SuppressTokensAtBeginLogitsProcessor(generation_config.begin_suppress_tokens, begin_index));\n    }\n\n    // DEPRECATED: https://github.com/huggingface/transformers/pull/29485\n    // if (generation_config.forced_decoder_ids !== null) {\n    //     processors.push(new ForceTokensLogitsProcessor(generation_config.forced_decoder_ids));\n    // }\n\n    // 8. prepare batched CFG externally\n    if (generation_config.guidance_scale !== null && generation_config.guidance_scale > 1) {\n      processors.push(new ClassifierFreeGuidanceLogitsProcessor(generation_config.guidance_scale));\n    }\n\n    if (logits_processor !== null) {\n      processors.extend(logits_processor as any);\n    }\n\n    // `LogitNormalization` should always be the last logit processor, when present\n    // if (generation_config.renormalize_logits === true) {\n    //     processors.push(new LogitNormalization());\n    // }\n\n    return processors;\n  }\n\n  /**\n   * This function merges multiple generation configs together to form a final generation config to be used by the model for text generation.\n   * It first creates an empty `GenerationConfig` object, then it applies the model's own `generation_config` property to it. Finally, if a `generation_config` object was passed in the arguments, it overwrites the corresponding properties in the final config with those of the passed config object.\n   * @param {GenerationConfig|null} generation_config A `GenerationConfig` object containing generation parameters.\n   * @param {Object} kwargs Additional generation parameters to be used in place of those in the `generation_config` object.\n   * @returns {GenerationConfig} The final generation config object to be used by the model for text generation.\n   */\n  _prepare_generation_config(\n    generation_config: GenerationConfig | null,\n    kwargs: any,\n    cls = GenerationConfig,\n  ) {\n    // Create empty generation config (contains defaults)\n    // We pass `this.config` so that if `eos_token_id` or `bos_token_id` exist in the model's config, we will use them\n    const config = { ...this.config };\n    for (const key of ['decoder', 'generator', 'text_config']) {\n      // Special case: some models have generation attributes set in the decoder.\n      // Use them if still unset in the generation config.\n      if (key in config) {\n        Object.assign(config, (config as any)[key]);\n      }\n    }\n\n    const gen_config = new cls(config);\n\n    // Apply model's generation config, if it exists\n    Object.assign(gen_config, this.generation_config ?? {});\n\n    // Next, use any generation config specified by the user\n    // when calling `generate`\n    if (generation_config) {\n      Object.assign(gen_config, generation_config);\n    }\n\n    // Finally, if any kwargs were passed, use them to overwrite\n    if (kwargs) {\n      Object.assign(gen_config, pick(kwargs, Object.getOwnPropertyNames(gen_config)));\n    }\n\n    return gen_config;\n  }\n\n  /**\n   *\n   * @param {GenerationConfig} generation_config\n   * @param {StoppingCriteriaList} [stopping_criteria=null]\n   */\n  _get_stopping_criteria(generation_config: GenerationConfig, stopping_criteria = null) {\n    const criteria = new StoppingCriteriaList();\n\n    if (generation_config.max_length !== null) {\n      criteria.push(new MaxLengthCriteria(generation_config.max_length, this.config.max_position_embeddings ?? null));\n    }\n    // if (generation_config.max_time !== null) {\n    //     criteria.push(new MaxTimeCriteria(generation_config.max_time));\n    // }\n    if (generation_config.eos_token_id !== null) {\n      criteria.push(new EosTokenCriteria(generation_config.eos_token_id));\n    }\n\n    if (stopping_criteria) {\n      criteria.extend(stopping_criteria);\n    }\n    return criteria;\n  }\n\n  /**\n   * Confirms that the model class is compatible with generation.\n   * If not, raises an exception that points to the right class to use.\n   */\n  _validate_model_class() {\n    if (!this.can_generate) {\n      const generate_compatible_mappings = [\n        MODEL_FOR_CAUSAL_LM_MAPPING_NAMES,\n        // MODEL_FOR_CAUSAL_IMAGE_MODELING_MAPPING, // TODO\n        MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES,\n        MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES,\n      ];\n\n      const modelName = MODEL_CLASS_TO_NAME_MAPPING.get(this.constructor);\n\n      const generate_compatible_classes = new Set();\n      const modelType = this.config.model_type;\n      for (const model_mapping of generate_compatible_mappings) {\n        const supported_models = model_mapping.get(modelType ?? 'custom');\n        if (supported_models) {\n          generate_compatible_classes.add(supported_models[0]);\n        }\n      }\n\n      let errorMessage = `The current model class (${modelName}) is not compatible with \\`.generate()\\`, as it doesn't have a language model head.`;\n      if (generate_compatible_classes.size > 0) {\n        errorMessage += ` Please use the following class instead: ${[...generate_compatible_classes].join(', ')}`;\n      }\n      throw Error(errorMessage);\n    }\n  }\n\n  prepare_inputs_for_generation(\n    this: PreTrainedModel,\n    ...args: [Tensor, Record<string, unknown>, GenerationConfig]\n  ) {\n    return this._prepare_inputs_for_generation(this, ...args);\n  }\n\n  /**\n   *\n   * @param {Object} inputs\n   * @param {bigint[][]} inputs.generated_input_ids\n   * @param {Object} inputs.outputs\n   * @param {Object} inputs.model_inputs\n   * @param {boolean} inputs.is_encoder_decoder\n   * @returns {Object} The updated model inputs for the next generation iteration.\n   */\n  _update_model_kwargs_for_generation({\n    generated_input_ids,\n    outputs,\n    model_inputs,\n    is_encoder_decoder,\n  }: {\n    generated_input_ids: bigint[][];\n    outputs: Record<string, unknown>;\n    model_inputs: Record<string, unknown>;\n    is_encoder_decoder: boolean;\n  }) {\n    // update past_key_values\n    model_inputs['past_key_values'] = this.getPastKeyValues(outputs, (model_inputs.past_key_values as any));\n\n    // update inputs for next run\n    model_inputs['input_ids'] = new Tensor('int64', generated_input_ids.flat(), [generated_input_ids.length, 1]);\n\n    if (!is_encoder_decoder) {\n      // update attention mask\n      model_inputs.attention_mask = cat(\n        [(model_inputs.attention_mask as any), ones([(model_inputs.attention_mask as any).dims[0], 1])],\n        1,\n      );\n    } else if ('decoder_attention_mask' in model_inputs) {\n      // TODO: update decoder attention mask if the model requires it\n    }\n\n    // force recreate position_ids in next iteration\n    model_inputs['position_ids'] = null;\n\n    return model_inputs;\n  }\n\n  /**\n   * This function extracts the model-specific `inputs` for generation.\n   * @param {Object} params\n   * @param {Tensor} [params.inputs=null]\n   * @param {number} [params.bos_token_id=null]\n   * @param {Record<string, Tensor|number[]>} [params.model_kwargs]\n   * @returns {{inputs_tensor: Tensor, model_inputs: Record<string, Tensor>, model_input_name: string}} The model-specific inputs for generation.\n   */\n  _prepare_model_inputs({\n    inputs,\n    bos_token_id,\n    model_kwargs,\n  }: {\n    inputs: Tensor | null;\n    bos_token_id: number | null;\n    model_kwargs: Record<string, any>;\n  }) {\n    const model_inputs = pick(model_kwargs, this.forward_params);\n    const input_name = this.main_input_name;\n    if (input_name in model_inputs) {\n      if (inputs) {\n        throw new Error(\n          '`inputs`: {inputs}` were passed alongside {input_name} which is not allowed. ' +\n          'Make sure to either pass {inputs} or {input_name}=...',\n        );\n      }\n    } else {\n      model_inputs[input_name] = inputs;\n    }\n\n    const inputs_tensor = model_inputs[input_name];\n\n    return { inputs_tensor, model_inputs, model_input_name: input_name };\n  }\n\n  async _prepare_encoder_decoder_kwargs_for_generation({\n    inputs_tensor,\n    model_inputs,\n    model_input_name,\n    generation_config,\n  }: {\n    inputs_tensor: Tensor;\n    model_inputs: Record<string, unknown>;\n    model_input_name: string;\n    generation_config: GenerationConfig;\n  }) {\n    if (\n      this.sessions['model'].inputNames.includes('inputs_embeds') &&\n      !model_inputs.inputs_embeds &&\n      '_prepare_inputs_embeds' in this\n    ) {\n      // Encoder expects `inputs_embeds` instead of `input_ids`\n      const { input_ids, pixel_values, attention_mask, ...kwargs } = model_inputs;\n      // @ts-ignore\n      const prepared_inputs = await this._prepare_inputs_embeds(model_inputs);\n      model_inputs = {\n        ...kwargs,\n        ...pick(prepared_inputs, ['inputs_embeds', 'attention_mask']),\n      };\n    }\n    let { last_hidden_state } = await encoderForward(this, model_inputs);\n\n    // for classifier free guidance we need to add a 'null' input to our encoder hidden states\n    if (generation_config.guidance_scale !== null && generation_config.guidance_scale > 1) {\n      last_hidden_state = cat([last_hidden_state, full_like(last_hidden_state, 0.0)], 0);\n\n      if ('attention_mask' in model_inputs) {\n        model_inputs['attention_mask'] = cat(\n          [(model_inputs['attention_mask'] as any), zeros_like((model_inputs['attention_mask'] as any))],\n          0,\n        );\n      }\n    } else if (model_inputs.decoder_input_ids) {\n      // Ensure that the encoder outputs have the same batch size as the decoder inputs,\n      // allowing for more efficient batched generation for single inputs\n      const decoder_input_ids_batch_size = toI64Tensor(model_inputs.decoder_input_ids).dims[0];\n      if (decoder_input_ids_batch_size !== last_hidden_state.dims[0]) {\n        if (last_hidden_state.dims[0] !== 1) {\n          throw new Error(\n            `The encoder outputs have a different batch size (${last_hidden_state.dims[0]}) than the decoder inputs (${decoder_input_ids_batch_size}).`,\n          );\n        }\n        last_hidden_state = cat(\n          Array.from({ length: decoder_input_ids_batch_size }, () => last_hidden_state),\n          0,\n        );\n      }\n    }\n    model_inputs['encoder_outputs'] = last_hidden_state;\n\n    return model_inputs;\n  }\n\n  /**\n   * Prepares `decoder_input_ids` for generation with encoder-decoder models\n   * @param {*} param0\n   */\n  _prepare_decoder_input_ids_for_generation({\n    batch_size,\n    model_input_name,\n    model_kwargs,\n    decoder_start_token_id,\n    bos_token_id,\n    generation_config,\n  }: {\n    batch_size: number;\n    model_input_name: string;\n    model_kwargs: Record<string, unknown>;\n    decoder_start_token_id: number | null;\n    bos_token_id: number | null;\n    generation_config: GenerationConfig;\n  }) {\n    let { decoder_input_ids, ...model_inputs } = model_kwargs;\n\n    // Prepare input ids if the user has not defined `decoder_input_ids` manually.\n    if (!(decoder_input_ids instanceof Tensor)) {\n      if (!decoder_input_ids) {\n        decoder_start_token_id ??= bos_token_id;\n\n        if (this.config.model_type === 'musicgen') {\n          // Custom logic (TODO: move to Musicgen class)\n          decoder_input_ids = Array.from(\n            {\n              // @ts-expect-error TS2339\n              length: batch_size * this.config.decoder.num_codebooks,\n            },\n            () => [decoder_start_token_id],\n          );\n        } else if (Array.isArray(decoder_start_token_id)) {\n          if (decoder_start_token_id.length !== batch_size) {\n            throw new Error(\n              `\\`decoder_start_token_id\\` expcted to have length ${batch_size} but got ${decoder_start_token_id.length}`,\n            );\n          }\n          decoder_input_ids = decoder_start_token_id;\n        } else {\n          decoder_input_ids = Array.from(\n            {\n              length: batch_size,\n            },\n            () => [decoder_start_token_id],\n          );\n        }\n      } else if (!Array.isArray((decoder_input_ids as any)[0])) {\n        // Correct batch size\n        decoder_input_ids = Array.from(\n          {\n            length: batch_size,\n          },\n          () => decoder_input_ids,\n        );\n      }\n      decoder_input_ids = toI64Tensor(decoder_input_ids);\n    }\n\n    model_kwargs['decoder_attention_mask'] = ones_like((decoder_input_ids as any));\n\n    return { input_ids: decoder_input_ids, model_inputs };\n  }\n\n  /**\n   * Generates sequences of token ids for models with a language modeling head.\n   * @param {import('./generation/parameters.js').GenerationFunctionParameters} options\n   * @returns {Promise<ModelOutput|Tensor>} The output of the model, which can contain the generated token ids, attentions, and scores.\n   */\n  async generate({\n    inputs = null,\n    generation_config = null,\n    logits_processor = null,\n    stopping_criteria = null,\n    streamer = null,\n    ...kwargs\n  }: any) {\n    this._validate_model_class();\n\n    // Update generation config with defaults and kwargs\n    generation_config = this._prepare_generation_config(generation_config, kwargs);\n\n    // 3. Define model inputs\n    let { inputs_tensor, model_inputs, model_input_name } = this._prepare_model_inputs({\n      inputs: inputs,\n      bos_token_id: null,\n      model_kwargs: kwargs,\n    });\n\n    const is_encoder_decoder = this.config.is_encoder_decoder;\n\n    // 4. Define other model kwargs\n    if (!is_encoder_decoder) {\n      // decoder-only models should use left-padding for generation\n    } else if (!('encoder_outputs' in model_inputs)) {\n      // if model is encoder decoder encoder_outputs are created\n      // and added to `model_kwargs`\n      model_inputs = await this._prepare_encoder_decoder_kwargs_for_generation({\n        inputs_tensor: (inputs_tensor as Tensor),\n        model_inputs: (model_inputs as Record<string, unknown>),\n        model_input_name: (model_input_name as string),\n        generation_config: (generation_config as GenerationConfig),\n      });\n    }\n\n    // 5. Prepare `input_ids` which will be used for auto-regressive generation\n    // TODO: Update to align with HF transformers' implementation\n    let input_ids;\n    if (is_encoder_decoder) {\n      // Generating from the encoder outputs\n      ({ input_ids, model_inputs } = this._prepare_decoder_input_ids_for_generation({\n        batch_size: (model_inputs[model_input_name] as any).dims.at(0),\n        model_input_name,\n        model_kwargs: model_inputs,\n        decoder_start_token_id: (generation_config as any).decoder_start_token_id,\n        bos_token_id: (generation_config as any).bos_token_id,\n        generation_config,\n      }));\n    } else {\n      input_ids = model_inputs[model_input_name];\n    }\n\n    // 6. Prepare `max_length` depending on other stopping criteria.\n    let input_ids_length = input_ids.dims.at(-1);\n\n    if (generation_config && (generation_config as any).max_new_tokens !== null) {\n      (generation_config as any).max_length = input_ids_length + (generation_config as any).max_new_tokens;\n    }\n\n    // input_ids_length = model_inputs[model_input_name].dims.at(1);\n    // // inputs instanceof Tensor ?  : inputs.length;\n\n    // // decoder-only\n    // if (input_ids_length === 0) {\n    //     throw Error(\"Must supply a non-empty array of input token ids.\")\n    // }\n\n    // let decoder_input_ids =\n    // generation_config.decoder_input_ids\n    // ?? generation_config.decoder_start_token_id\n    // ?? generation_config.bos_token_id\n    // ?? generation_config.eos_token_id;\n\n    // Update logits processor\n    // 8. prepare distribution pre_processing samplers\n    const prepared_logits_processor = this._get_logits_processor(generation_config, input_ids_length, logits_processor as any);\n\n    // 9. prepare stopping criteria\n    const prepared_stopping_criteria = this._get_stopping_criteria(generation_config, stopping_criteria as any);\n\n    // /** @type {number[]} */\n    // let eos_token_ids = generation_config.eos_token_id;\n    // if (eos_token_ids !== null && !Array.isArray(eos_token_ids)) {\n    //     eos_token_ids = [eos_token_ids];\n    // }\n\n    const numInputs = model_inputs[model_input_name].dims.at(0);\n\n    // TODO:\n    // done is a list of booleans to keep track of which inputs are done\n    // const done = new Array(numInputs).fill(false);\n    // For efficiency purposes, we remove completed rows from model_inputs\n    // when the beam is complete, and we keep track of the row index\n    // const rowIndexToBatchIndex = new Map();\n\n    const sampler = LogitsSampler.getSampler(generation_config);\n\n    // TODO make > numInputs\n    const scores = new Array(numInputs).fill(0);\n    /** @type {bigint[][]} */\n    const all_input_ids = input_ids.tolist();\n    if (streamer) {\n      (streamer as any).put(all_input_ids);\n    }\n    // const all_generated_input_ids = Array.from({ length: numInputs }, () => []);\n\n    // NOTE: For now, we don't support spawning new beams\n    // TODO: when we do, we simply copy past key values and accumulate into single large tensor\n\n    ////////////////////////////////////////////////////\n    // Generic search which handles 4 generation modes:\n    // - GenerationMode.GREEDY_SEARCH\n    // - GenerationMode.SAMPLE\n    // - GenerationMode.BEAM_SEARCH\n    // - GenerationMode.BEAM_SAMPLE\n    ////////////////////////////////////////////////////\n    let outputs;\n    let attentions = {};\n    while (true) {\n      // prepare model inputs\n      model_inputs = this.prepare_inputs_for_generation(all_input_ids, model_inputs, generation_config);\n      outputs = await this.forward(model_inputs);\n\n      if ((generation_config as any).output_attentions && (generation_config as any).return_dict_in_generate) {\n        // Get attentions if they are present\n        const token_attentions = this.getAttentions(outputs);\n        for (const key in token_attentions) {\n          if (!(key in attentions)) {\n            (attentions as any)[key] = [];\n          }\n          (attentions as any)[key].push(token_attentions[key]);\n        }\n      }\n\n      // Logits are of the form [batch_size, out_seq_length, vocab_size]\n      // In most cases, this will be [batch_size, 1, vocab_size]\n      // So, we select the last token's logits:\n      // (equivalent to `logits = outputs.logits[:, -1, :]`)\n      const logits = outputs.logits.slice(null, -1, null);\n\n      const next_tokens_scores = prepared_logits_processor._call(all_input_ids, logits);\n\n      /** @type {[bigint][]} */\n      const generated_input_ids = [];\n      // const new_kv_cache = [];// NOTE: Only used for beam search when concatenating new kv\n      // Loop over each batch\n      for (let batch_idx = 0; batch_idx < next_tokens_scores.dims.at(0); ++batch_idx) {\n        const logs = next_tokens_scores[batch_idx];\n\n        const sampledTokens = await sampler.sample(logs);\n        for (const [newTokenId, logProb] of sampledTokens) {\n          const bigint = BigInt(newTokenId);\n          // TODO: If branching, use previous beam as a starting point\n          // update generated ids, model inputs, and length for next step\n          scores[batch_idx] += logProb;\n          all_input_ids[batch_idx].push(bigint);\n          generated_input_ids.push([bigint]);\n\n          // TODO: Support beam search\n          break;\n        }\n      }\n      if (streamer) {\n        (streamer as any).put(generated_input_ids);\n      }\n\n      const stop = prepared_stopping_criteria._call(all_input_ids, scores);\n      if (stop.every(((x: any) => x))) {\n        break;\n      }\n\n      model_inputs = this._update_model_kwargs_for_generation({\n        generated_input_ids,\n        outputs,\n        model_inputs,\n        is_encoder_decoder,\n      });\n    }\n\n    if (streamer) {\n      (streamer as any).end();\n    }\n\n    // Retrieve and dispose all final past key values (including encoder attentions)\n    const past_key_values = this.getPastKeyValues(outputs, (model_inputs as any).past_key_values, true);\n\n    // TODO: ensure all_input_ids is padded correctly...\n    const sequences = new Tensor('int64', all_input_ids.flat(), [all_input_ids.length, all_input_ids[0].length]);\n\n    if ((generation_config as any).return_dict_in_generate) {\n      return {\n        sequences,\n        past_key_values,\n        ...attentions,\n        // TODO:\n        // scores,\n        // logits,\n      };\n    } else {\n      // Dispose all remaining tensors\n      for (const tensor of Object.values(outputs)) {\n        if ((tensor as any).location === 'gpu-buffer') {\n          (tensor as any).dispose();\n        }\n      }\n      return sequences;\n    }\n  }\n\n  /**\n   * Returns an object containing past key values from the given decoder results object.\n   *\n   * @param {Object} decoderResults The decoder results object.\n   * @param {Object} pastKeyValues The previous past key values.\n   * @returns {Object} An object containing past key values.\n   */\n  getPastKeyValues(\n    decoderResults: Record<string, unknown>,\n    pastKeyValues: Record<string, unknown>,\n    disposeEncoderPKVs = false,\n  ) {\n    const pkvs = Object.create(null);\n\n    for (const name in decoderResults) {\n      if (name.startsWith('present')) {\n        const newName = name.replace('present', 'past_key_values');\n        const is_encoder_pkv = name.includes('encoder');\n        if (is_encoder_pkv && pastKeyValues) {\n          // Optimization introduced by optimum to reuse past key values.\n          // So, we just replace the constant outputs (`decoderResults[name]`) with the previous past key values.\n          // https://github.com/huggingface/optimum/blob/0bf2c05fb7e1182b52d21b703cfc95fd9e4ea3dc/optimum/onnxruntime/base.py#L677-L704\n          pkvs[newName] = pastKeyValues[newName];\n        } else {\n          // decoder or using first encoder PKVs\n          pkvs[newName] = decoderResults[name];\n        }\n\n        if (pastKeyValues && (!is_encoder_pkv || disposeEncoderPKVs)) {\n          // - Always dispose decoder PKVs\n          // - Only dispose encoder past key values when requested (after generation)\n          const t = pastKeyValues[newName];\n          if ((t as any).location === 'gpu-buffer') {\n            (t as any).dispose();\n          }\n        }\n      }\n    }\n    return pkvs;\n  }\n\n  /**\n   * Returns an object containing attentions from the given model output object.\n   *\n   * @param {Object} model_output The output of the model.\n   * @returns {{cross_attentions?: Tensor[]}} An object containing attentions.\n   */\n  getAttentions(model_output: Record<string, unknown>) {\n    const attentions: Record<string, unknown[]> = {};\n\n    for (const attnName of ['cross_attentions', 'encoder_attentions', 'decoder_attentions']) {\n      for (const name in model_output) {\n        if (name.startsWith(attnName)) {\n          if (!(attnName in attentions)) {\n            attentions[attnName] = [];\n          }\n          attentions[attnName].push(model_output[name]);\n        }\n      }\n    }\n    return attentions;\n  }\n\n  /**\n   * Adds past key values to the decoder feeds object. If pastKeyValues is null, creates new tensors for past key values.\n   *\n   * @param {Object} decoderFeeds The decoder feeds object to add past key values to.\n   * @param {Object} pastKeyValues An object containing past key values.\n   */\n  addPastKeyValues(decoderFeeds: Record<string, any>, pastKeyValues: Record<string, any>) {\n    if (pastKeyValues) {\n      Object.assign(decoderFeeds, pastKeyValues);\n    } else {\n      const session = this.sessions['decoder_model_merged'] ?? this.sessions['model'];\n      const dtype = session?.config?.kv_cache_dtype ?? 'float32';\n      const empty = dtype === 'float16' ? new Uint16Array() : [];\n\n      const batch_size = (decoderFeeds[this.main_input_name] ?? decoderFeeds.attention_mask)?.dims?.[0] ?? 1;\n      const shapes = getKeyValueShapes(this.config, { batch_size });\n\n      for (const name in shapes) {\n        decoderFeeds[name] = new Tensor(dtype, empty, shapes[name]);\n      }\n    }\n  }\n\n  async encode_image({ pixel_values }: { pixel_values: Tensor }) {\n    // image_inputs === { pixel_values }\n    const features = (await sessionRun(this.sessions['vision_encoder'], { pixel_values })).image_features;\n    // @ts-expect-error TS2339\n    if (!this.config.num_image_tokens) {\n      console.warn(\n        'The number of image tokens was not set in the model configuration. ' +\n        `Setting it to the number of features detected by the vision encoder (${features.dims[1]}).`,\n      );\n      // @ts-expect-error TS2339\n      this.config.num_image_tokens = features.dims[1];\n    }\n    return features;\n  }\n\n  async encode_text({ input_ids }: { input_ids: Tensor }) {\n    // text_inputs === { input_ids, attention_mask }\n    return (await sessionRun(this.sessions['embed_tokens'], { input_ids })).inputs_embeds;\n  }\n}\n\n//////////////////////////////////////////////////\n// Base model output class\nexport class ModelOutput { }\n\n/**\n * Base class for model's outputs, with potential hidden states and attentions.\n */\nexport class BaseModelOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.last_hidden_state Sequence of hidden-states at the output of the last layer of the model.\n   * @param {Tensor} [output.hidden_states] Hidden-states of the model at the output of each layer plus the optional initial embedding outputs.\n   * @param {Tensor} [output.attentions] Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.\n   */\n  last_hidden_state: Tensor;\n  hidden_states: Tensor[] | null;\n  attentions: Tensor[] | null;\n\n  constructor({\n    last_hidden_state,\n    hidden_states = null,\n    attentions = null,\n  }: {\n    last_hidden_state: Tensor;\n    hidden_states?: Tensor[] | null;\n    attentions?: Tensor[] | null;\n  }) {\n    super();\n    this.last_hidden_state = last_hidden_state;\n    this.hidden_states = hidden_states;\n    this.attentions = attentions;\n  }\n}\n\n//////////////////////////////////////////////////\n// Audio Spectrogram Transformer (AST) models\nexport class ASTPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare AST Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class ASTModel extends ASTPreTrainedModel { }\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Whisper models\nexport class WhisperPreTrainedModel extends PreTrainedModel {\n  requires_attention_mask = false;\n  main_input_name = 'input_features';\n  forward_params = [\n    'input_features',\n    'attention_mask',\n    'decoder_input_ids',\n    'decoder_attention_mask',\n    'past_key_values',\n  ];\n}\n\n/**\n * WhisperModel class for training Whisper models without a language model head.\n */\nexport class WhisperModel extends WhisperPreTrainedModel { }\n\n/**\n * WhisperForConditionalGeneration class for generating conditional outputs from Whisper models.\n */\nexport class WhisperForConditionalGeneration extends WhisperPreTrainedModel {\n  _prepare_generation_config(generation_config: GenerationConfig, kwargs: Record<string, unknown>) {\n    return /** @type {WhisperGenerationConfig} */ super._prepare_generation_config(\n      generation_config,\n      kwargs,\n      WhisperGenerationConfig,\n    );\n  }\n\n  /**\n   *\n   * @param {WhisperGenerationConfig} generation_config\n   */\n  _retrieve_init_tokens(generation_config: WhisperGenerationConfig) {\n    // prefix tokens are of the form:\n    //  - Multilingual: <|startoftranscript|> <|lang_id|> <|task|> [<|notimestamps|>]\n    //  - English-only: <|startoftranscript|> [<|notimestamps|>]\n\n    // 1. Handle <|startoftranscript|> token\n    const init_tokens = [generation_config.decoder_start_token_id];\n\n    // 2. Handle <|lang_id|> and <|task> tokens\n    let language: string | null = generation_config.language;\n    const task = generation_config.task;\n    if (generation_config.is_multilingual) {\n      if (!language) {\n        // TODO: Implement language detection\n        console.warn('No language specified - defaulting to English (en).');\n        language = 'en';\n      }\n\n      // Add language token\n      const language_code = whisper_language_to_code(language);\n      const language_token = `<|${language_code}|>`;\n      if (generation_config.lang_to_id) {\n        init_tokens.push(generation_config.lang_to_id[language_token]);\n      }\n\n      // Add task token\n      // NOTE: Defaults to 'transcribe' if no task is specified\n      if (!generation_config.task_to_id) throw new Error('task_to_id mapping is required but was not provided');\n      init_tokens.push(generation_config.task_to_id[task ?? 'transcribe']);\n    } else if (language || task) {\n      throw new Error(\n        'Cannot specify `task` or `language` for an English-only model. If the model is intended to be multilingual, pass `is_multilingual=true` to generate, or update the generation config.',\n      );\n    }\n\n    // 3. Handle <|notimestamps|> token\n    if (\n      !generation_config.return_timestamps &&\n      generation_config.no_timestamps_token_id &&\n      init_tokens.at(-1) !== generation_config.no_timestamps_token_id\n    ) {\n      init_tokens.push(generation_config.no_timestamps_token_id);\n    } else if (generation_config.return_timestamps && init_tokens.at(-1) === generation_config.no_timestamps_token_id) {\n      console.warn(\n        '<|notimestamps|> prompt token is removed from generation_config since `return_timestamps` is set to `true`.',\n      );\n      init_tokens.pop();\n    }\n\n    // let's make sure we don't pass `null` tokens as prompt tokens\n    return init_tokens.filter((token) => token != null);\n  }\n\n  /**\n   * Transcribes or translates log-mel input features to a sequence of auto-regressively generated token ids.\n   * @param {import('./models/whisper/generation_whisper.js').WhisperGenerationFunctionParameters} options\n   * @returns {Promise<ModelOutput|Tensor>} The output of the model, which can contain the generated token ids, attentions, and scores.\n   */\n  async generate({\n    inputs = null,\n    generation_config = null,\n    logits_processor = null,\n    stopping_criteria = null,\n\n    // Whisper-specific options (passed to kwargs)\n    // prompt_ids = null,\n    // language = null,\n    // task = null,\n\n    ...kwargs\n  }: any) {\n    generation_config = this._prepare_generation_config(generation_config, kwargs);\n\n    const init_tokens = kwargs.decoder_input_ids ?? this._retrieve_init_tokens(generation_config);\n\n    if (generation_config.return_timestamps) {\n      logits_processor ??= new LogitsProcessorList();\n      logits_processor.push(new WhisperTimeStampLogitsProcessor(generation_config, init_tokens));\n    }\n\n    if (generation_config.begin_suppress_tokens) {\n      logits_processor ??= new LogitsProcessorList();\n      logits_processor.push(\n        new SuppressTokensAtBeginLogitsProcessor(generation_config.begin_suppress_tokens, init_tokens.length),\n      );\n    }\n\n    if (generation_config.return_token_timestamps) {\n      if (!generation_config.alignment_heads) {\n        throw new Error(\n          'Model generation config has no `alignment_heads`, token-level timestamps not available. ' +\n          'See https://gist.github.com/hollance/42e32852f24243b748ae6bc1f985b13a on how to add this property to the generation config.',\n        );\n      }\n\n      if (generation_config.task === 'translate') {\n        console.warn(\"Token-level timestamps may not be reliable for task 'translate'.\");\n      }\n\n      generation_config.output_attentions = true;\n      generation_config.return_dict_in_generate = true;\n    }\n\n    const outputs: any = await super.generate({\n      inputs,\n      generation_config,\n      logits_processor,\n      decoder_input_ids: init_tokens,\n      ...kwargs,\n    });\n\n    if (generation_config.return_token_timestamps) {\n      (outputs as any)['token_timestamps'] = this._extract_token_timestamps(\n        outputs,\n        generation_config.alignment_heads,\n        generation_config.num_frames,\n      );\n    }\n\n    return outputs;\n  }\n\n  /**\n   * Calculates token-level timestamps using the encoder-decoder cross-attentions and\n   * dynamic time-warping (DTW) to map each output token to a position in the input audio.\n   * If `num_frames` is specified, the encoder-decoder cross-attentions will be cropped before applying DTW.\n   * @param {Object} generate_outputs Outputs generated by the model\n   * @param {Tensor[][]} generate_outputs.cross_attentions The cross attentions output by the model\n   * @param {Tensor} generate_outputs.sequences The sequences output by the model\n   * @param {number[][]} alignment_heads Alignment heads of the model\n   * @param {number} [num_frames=null] Number of frames in the input audio.\n   * @param {number} [time_precision=0.02] Precision of the timestamps in seconds\n   * @returns {Tensor} tensor containing the timestamps in seconds for each predicted token\n   */\n  _extract_token_timestamps(\n    generate_outputs: Record<string, unknown>,\n    alignment_heads: number[][],\n    num_frames = null,\n    time_precision = 0.02,\n  ) {\n    if (!generate_outputs.cross_attentions) {\n      throw new Error(\n        'Model outputs must contain cross attentions to extract timestamps. ' +\n        'This is most likely because the model was not exported with `output_attentions=True`.',\n      );\n    }\n    if (num_frames == null) {\n      console.warn(\n        '`num_frames` has not been set, meaning the entire audio will be analyzed. ' +\n        'This may lead to inaccurate token-level timestamps for short audios (< 30 seconds).',\n      );\n    }\n\n    // @ts-expect-error TS2339\n    let median_filter_width = this.config.median_filter_width;\n    if (median_filter_width === undefined) {\n      console.warn('Model config has no `median_filter_width`, using default value of 7.');\n      median_filter_width = 7;\n    }\n\n    // TODO: Improve batch processing\n    const batch = generate_outputs.cross_attentions;\n    // Create a list with `decoder_layers` elements, each a tensor of shape\n    // (batch size, attention_heads, output length, input length).\n    const cross_attentions = Array.from(\n      { length: (this.config as any).decoder_layers },\n      // Concatenate the cross attentions for each layer across sequence length dimension.\n      (_, i) =>\n        cat(\n          (batch as any).map((x: any) => x[i]),\n          2,\n        ),\n    );\n\n    const weights = stack(\n      alignment_heads.map(([l, h]) => {\n        if (l >= cross_attentions.length) {\n          throw new Error(\n            `Layer index ${l} is out of bounds for cross attentions (length ${cross_attentions.length}).`,\n          );\n        }\n        return num_frames\n          ? cross_attentions[l].slice(null, h, null, [0, num_frames])\n          : cross_attentions[l].slice(null, h);\n      }),\n    ).transpose(1, 0, 2, 3);\n\n    const [std, calculatedMean] = std_mean(weights, -2, 0, true);\n\n    // Normalize and smoothen the weights.\n    const smoothedWeights = weights.clone(); // [1, 8, seqLength, 1500]\n\n    for (let a = 0; a < smoothedWeights.dims[0]; ++a) {\n      const aTensor = smoothedWeights[a]; // [8, seqLength, 1500]\n\n      for (let b = 0; b < aTensor.dims[0]; ++b) {\n        const bTensor = aTensor[b]; // [seqLength, 1500]\n\n        const stdTensorData = std[a][b][0].data; // [1500]\n        const meanTensorData = calculatedMean[a][b][0].data; // [1500]\n\n        for (let c = 0; c < bTensor.dims[0]; ++c) {\n          let cTensorData = bTensor[c].data; // [1500]\n          for (let d = 0; d < cTensorData.length; ++d) {\n            cTensorData[d] = (cTensorData[d] - meanTensorData[d]) / stdTensorData[d];\n          }\n\n          // Apply median filter.\n          (cTensorData as any).set(medianFilter((cTensorData as any), median_filter_width));\n        }\n      }\n    }\n\n    // Average the different cross-attention heads.\n    const batchedMatrices = [mean(smoothedWeights, 1)];\n\n    const timestampsShape = (generate_outputs.sequences as any).dims;\n\n    const timestamps = new Tensor(\n      'float32',\n      new Float32Array(timestampsShape[0] * timestampsShape[1]),\n      timestampsShape,\n    );\n\n    // Perform dynamic time warping on each element of the batch.\n    for (let batch_idx = 0; batch_idx < timestampsShape[0]; ++batch_idx) {\n      // NOTE: Since we run only one batch at a time, we can squeeze to get the same dimensions\n      // as the python implementation\n      const matrix = batchedMatrices[batch_idx].neg().squeeze_(0);\n      const [text_indices, time_indices] = dynamic_time_warping(matrix.tolist());\n\n      const diffs = Array.from({ length: text_indices.length - 1 }, (v, i) => text_indices[i + 1] - text_indices[i]);\n      const jumps = mergeArrays([1], diffs).map((x) => !!x); // convert to boolean\n\n      const jump_times = [];\n      for (let i = 0; i < jumps.length; ++i) {\n        if (jumps[i]) {\n          // NOTE: No point in rounding here, since we set to Float32Array later\n          jump_times.push(time_indices[i] * time_precision);\n        }\n      }\n      (timestamps[batch_idx].data as any).set(jump_times, 1);\n    }\n\n    return timestamps;\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Moonshine models\nexport class MoonshinePreTrainedModel extends PreTrainedModel {\n  requires_attention_mask = false;\n  main_input_name = 'input_values';\n  forward_params = ['input_values', 'decoder_input_ids', 'past_key_values'];\n}\n\n/**\n * MoonshineModel class for training Moonshine models without a language model head.\n */\nexport class MoonshineModel extends MoonshinePreTrainedModel { }\n\nexport class MoonshineForConditionalGeneration extends MoonshinePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// LLaVa Models\nexport class LlavaPreTrainedModel extends PreTrainedModel {\n  forward_params = ['input_ids', 'attention_mask', 'pixel_values', 'position_ids', 'past_key_values'];\n}\n\n/**\n * The LLAVA model which consists of a vision backbone and a language model.\n */\nexport class LlavaForConditionalGeneration extends LlavaPreTrainedModel {\n  _merge_input_ids_with_image_features({ inputs_embeds, image_features, input_ids, attention_mask }: any) {\n    // @ts-expect-error TS2339\n    const image_token_index = this.config.image_token_index;\n\n    const idsList = input_ids.tolist();\n\n    // NOTE: we use .findIndex instead of .indexOf to perform weak comparison (==) between BigInt and Number\n    const indexOfImage = idsList.map((x: any) => x.findIndex((x: any) => x == image_token_index));\n\n    const noImages = indexOfImage.every((x: any) => x === -1);\n    const allImages = indexOfImage.every((x: any) => x !== -1);\n    if (!noImages && !allImages) {\n      // Check for padding reasons\n      throw new Error('Every input should contain either 0 or 1 image token.');\n    }\n\n    if (noImages) {\n      return {\n        inputs_embeds,\n        attention_mask,\n      };\n    }\n\n    const stacked = [];\n    const stacked_attention_mask = [];\n    for (let i = 0; i < indexOfImage.length; ++i) {\n      const index = indexOfImage[i];\n\n      const e = inputs_embeds[i];\n      const im = image_features[i];\n      const am = attention_mask[i];\n      stacked.push(cat([e.slice([0, index]), im, e.slice([index + 1, e.dims[0]])], 0));\n\n      stacked_attention_mask.push(\n        cat([am.slice([0, index]), ones([im.dims[0]]), am.slice([index + 1, am.dims[0]])], 0),\n      );\n    }\n\n    return {\n      inputs_embeds: stack(stacked, 0),\n      attention_mask: stack(stacked_attention_mask, 0),\n    };\n  }\n}\n//////////////////////////////////////////////////\n\nexport class LlavaOnevisionForConditionalGeneration extends LlavaForConditionalGeneration { } // NOTE: extends LlavaForConditionalGeneration\nexport class Moondream1ForConditionalGeneration extends LlavaForConditionalGeneration { } // NOTE: extends LlavaForConditionalGeneration\n\nexport class Florence2PreTrainedModel extends PreTrainedModel {\n  forward_params = [\n    // Encoder inputs\n    'input_ids',\n    'inputs_embeds',\n    'attention_mask',\n    'pixel_values',\n\n    // Decoder inputs\n    'encoder_outputs',\n    'decoder_input_ids',\n    'decoder_inputs_embeds',\n    'decoder_attention_mask',\n    'past_key_values',\n  ];\n  main_input_name = 'inputs_embeds';\n}\n\nexport class Florence2ForConditionalGeneration extends Florence2PreTrainedModel {\n  _merge_input_ids_with_image_features({\n    inputs_embeds,\n    image_features,\n    input_ids,\n    attention_mask,\n  }: {\n    inputs_embeds: Tensor;\n    image_features: Tensor;\n    input_ids: Tensor;\n    attention_mask: Tensor;\n  }) {\n    return {\n      inputs_embeds: cat(\n        [\n          image_features, // image embeds\n          inputs_embeds, // task prefix embeds\n        ],\n        1,\n      ),\n      attention_mask: cat(\n        [\n          ones(image_features.dims.slice(0, 2)), // image attention mask\n          attention_mask, // task prefix attention mask\n        ],\n        1,\n      ),\n    };\n  }\n\n  async _prepare_inputs_embeds({\n    input_ids,\n    pixel_values,\n    inputs_embeds,\n    attention_mask,\n  }: {\n    input_ids: Tensor | null;\n    pixel_values: Tensor | null;\n    inputs_embeds: Tensor | null;\n    attention_mask: Tensor | null;\n  }) {\n    if (!input_ids && !pixel_values) {\n      throw new Error('Either `input_ids` or `pixel_values` should be provided.');\n    }\n\n    // 1. Possibly, extract the input embeddings\n    let text_features, image_features;\n    if (input_ids) {\n      text_features = await this.encode_text({ input_ids });\n    }\n    if (pixel_values) {\n      image_features = await this.encode_image({ pixel_values });\n    }\n\n    // 2. Possibly, merge text and images\n    if (text_features && image_features) {\n      ({ inputs_embeds, attention_mask } = this._merge_input_ids_with_image_features({\n        inputs_embeds: text_features,\n        image_features,\n        input_ids: input_ids as Tensor,\n        attention_mask: attention_mask as Tensor,\n      }));\n    } else {\n      inputs_embeds = text_features || image_features;\n    }\n\n    return { inputs_embeds, attention_mask };\n  }\n\n  async forward({\n    input_ids,\n    pixel_values,\n    attention_mask,\n    decoder_input_ids,\n    decoder_attention_mask,\n    encoder_outputs,\n    past_key_values,\n\n    inputs_embeds,\n    decoder_inputs_embeds,\n  }: any) {\n    if (!inputs_embeds) {\n      ({ inputs_embeds, attention_mask } = await this._prepare_inputs_embeds({\n        input_ids,\n        pixel_values,\n        inputs_embeds,\n        attention_mask,\n      }));\n    }\n\n    if (!encoder_outputs) {\n      // Must compute encoder outputs\n      let { last_hidden_state } = await encoderForward(this, { inputs_embeds, attention_mask });\n      encoder_outputs = last_hidden_state;\n    }\n\n    if (!decoder_inputs_embeds) {\n      if (!decoder_input_ids) {\n        throw new Error('Either `decoder_input_ids` or `decoder_inputs_embeds` should be provided.');\n      }\n      decoder_inputs_embeds = await this.encode_text({ input_ids: decoder_input_ids });\n    }\n\n    const decoderFeeds = {\n      inputs_embeds: decoder_inputs_embeds,\n      attention_mask: decoder_attention_mask,\n      encoder_attention_mask: attention_mask,\n      encoder_hidden_states: encoder_outputs,\n      past_key_values,\n    };\n    const decoder_outputs = await decoderForward(this, decoderFeeds, true);\n    return decoder_outputs;\n  }\n}\n\nexport class PaliGemmaPreTrainedModel extends PreTrainedModel {\n  forward_params = [\n    'input_ids',\n    // 'inputs_embeds',\n    'attention_mask',\n    'pixel_values',\n    'position_ids',\n    'past_key_values',\n  ];\n}\n\nexport class PaliGemmaForConditionalGeneration extends PaliGemmaPreTrainedModel {\n  _merge_input_ids_with_image_features(kwargs: any) {\n    const vision_hidden_size = kwargs.image_features.dims.at(-1);\n    const reshaped_image_hidden_states = kwargs.image_features.view(-1, vision_hidden_size);\n\n    return default_merge_input_ids_with_image_features({\n      image_token_id: (this.config as any).image_token_index,\n      image_features: reshaped_image_hidden_states,\n      ...kwargs,\n    });\n  }\n}\n\n//////////////////////////////////////////////////\n// Idefics3 Models\nexport class Idefics3PreTrainedModel extends PreTrainedModel {\n  forward_params = [\n    'input_ids',\n    'attention_mask',\n    'pixel_values',\n    'pixel_attention_mask',\n    'position_ids',\n    'past_key_values',\n  ];\n}\n\n/**\n * The LLAVA model which consists of a vision backbone and a language model.\n */\nexport class Idefics3ForConditionalGeneration extends Idefics3PreTrainedModel {\n  async encode_image({ pixel_values, pixel_attention_mask }: { pixel_values: Tensor; pixel_attention_mask: Tensor }) {\n    const features = (await sessionRun(this.sessions['vision_encoder'], { pixel_values, pixel_attention_mask }))\n      .image_features;\n    return features;\n  }\n\n  _merge_input_ids_with_image_features(kwargs: any) {\n    const vision_hidden_size = kwargs.image_features.dims.at(-1);\n    const reshaped_image_hidden_states = kwargs.image_features.view(-1, vision_hidden_size);\n\n    return default_merge_input_ids_with_image_features({\n      image_token_id: (this.config as any).image_token_id,\n      ...kwargs,\n      image_features: reshaped_image_hidden_states,\n    });\n  }\n}\n//////////////////////////////////////////////////\n\nexport class Phi3VPreTrainedModel extends PreTrainedModel {\n  forward_params = [\n    'input_ids',\n    'inputs_embeds',\n    'attention_mask',\n    'position_ids',\n    'pixel_values',\n    'image_sizes',\n    'past_key_values',\n  ];\n}\nexport class Phi3VForCausalLM extends Phi3VPreTrainedModel {\n  async forward({\n    // Produced by the tokenizer/processor:\n    input_ids = null,\n    attention_mask = null,\n    pixel_values = null,\n    image_sizes = null,\n\n    // Used during generation:\n    position_ids = null,\n    inputs_embeds = null,\n    past_key_values = null,\n\n    // Generic generation parameters\n    generation_config = null,\n    logits_processor = null,\n\n    // TODO: needed?\n    ...kwargs\n  }) {\n    if (!inputs_embeds) {\n      let image_features;\n      if (pixel_values && (input_ids as any).dims[1] !== 1) {\n        if (!image_sizes) {\n          throw new Error('`image_sizes` must be provided when `pixel_values` is provided.');\n        }\n\n        // Encode the image\n        ({ image_features } = await sessionRun(this.sessions['vision_encoder'], {\n          pixel_values,\n          image_sizes,\n        }));\n      } else {\n        const hidden_size = this.config.normalized_config.hidden_size;\n        image_features = new Tensor('float32', [], [0, hidden_size]);\n      }\n\n      ({ inputs_embeds } = await sessionRun(this.sessions['prepare_inputs_embeds'], {\n        input_ids,\n        image_features,\n      }));\n    }\n\n    const outputs = await decoderForward(\n      this,\n      {\n        inputs_embeds,\n        past_key_values,\n        attention_mask,\n        position_ids,\n        generation_config,\n        logits_processor,\n      },\n      false,\n    );\n    return outputs;\n  }\n}\n\n//////////////////////////////////////////////////\nexport class CLIPPreTrainedModel extends PreTrainedModel { }\n\n/**\n * CLIP Text and Vision Model with a projection layers on top\n *\n * **Example:** Perform zero-shot image classification with a `CLIPModel`.\n *\n * ```javascript\n * import { AutoTokenizer, AutoProcessor, CLIPModel, RawImage } from '@huggingface/transformers';\n *\n * // Load tokenizer, processor, and model\n * let tokenizer = await AutoTokenizer.from_pretrained('Xenova/clip-vit-base-patch16');\n * let processor = await AutoProcessor.from_pretrained('Xenova/clip-vit-base-patch16');\n * let model = await CLIPModel.from_pretrained('Xenova/clip-vit-base-patch16');\n *\n * // Run tokenization\n * let texts = ['a photo of a car', 'a photo of a football match']\n * let text_inputs = tokenizer(texts, { padding: true, truncation: true });\n *\n * // Read image and run processor\n * let image = await RawImage.read('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg');\n * let image_inputs = await processor(image);\n *\n * // Run model with both text and pixel inputs\n * let output = await model({ ...text_inputs, ...image_inputs });\n * // {\n * //   logits_per_image: Tensor {\n * //     dims: [ 1, 2 ],\n * //     data: Float32Array(2) [ 18.579734802246094, 24.31830596923828 ],\n * //   },\n * //   logits_per_text: Tensor {\n * //     dims: [ 2, 1 ],\n * //     data: Float32Array(2) [ 18.579734802246094, 24.31830596923828 ],\n * //   },\n * //   text_embeds: Tensor {\n * //     dims: [ 2, 512 ],\n * //     data: Float32Array(1024) [ ... ],\n * //   },\n * //   image_embeds: Tensor {\n * //     dims: [ 1, 512 ],\n * //     data: Float32Array(512) [ ... ],\n * //   }\n * // }\n * ```\n */\nexport class CLIPModel extends CLIPPreTrainedModel { }\n\n/**\n * The text model from CLIP without any head or projection on top.\n */\nexport class CLIPTextModel extends CLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'text_model',\n    });\n  }\n}\n\n/**\n * CLIP Text Model with a projection layer on top (a linear layer on top of the pooled output)\n *\n * **Example:** Compute text embeddings with `CLIPTextModelWithProjection`.\n *\n * ```javascript\n * import { AutoTokenizer, CLIPTextModelWithProjection } from '@huggingface/transformers';\n *\n * // Load tokenizer and text model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/clip-vit-base-patch16');\n * const text_model = await CLIPTextModelWithProjection.from_pretrained('Xenova/clip-vit-base-patch16');\n *\n * // Run tokenization\n * let texts = ['a photo of a car', 'a photo of a football match'];\n * let text_inputs = tokenizer(texts, { padding: true, truncation: true });\n *\n * // Compute embeddings\n * const { text_embeds } = await text_model(text_inputs);\n * // Tensor {\n * //   dims: [ 2, 512 ],\n * //   type: 'float32',\n * //   data: Float32Array(1024) [ ... ],\n * //   size: 1024\n * // }\n * ```\n */\nexport class CLIPTextModelWithProjection extends CLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'text_model',\n    });\n  }\n}\n\n/**\n * The vision model from CLIP without any head or projection on top.\n */\nexport class CLIPVisionModel extends CLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'vision_model',\n    });\n  }\n}\n\n/**\n * CLIP Vision Model with a projection layer on top (a linear layer on top of the pooled output)\n *\n * **Example:** Compute vision embeddings with `CLIPVisionModelWithProjection`.\n *\n * ```javascript\n * import { AutoProcessor, CLIPVisionModelWithProjection, RawImage} from '@huggingface/transformers';\n *\n * // Load processor and vision model\n * const processor = await AutoProcessor.from_pretrained('Xenova/clip-vit-base-patch16');\n * const vision_model = await CLIPVisionModelWithProjection.from_pretrained('Xenova/clip-vit-base-patch16');\n *\n * // Read image and run processor\n * let image = await RawImage.read('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg');\n * let image_inputs = await processor(image);\n *\n * // Compute embeddings\n * const { image_embeds } = await vision_model(image_inputs);\n * // Tensor {\n * //   dims: [ 1, 512 ],\n * //   type: 'float32',\n * //   data: Float32Array(512) [ ... ],\n * //   size: 512\n * // }\n * ```\n */\nexport class CLIPVisionModelWithProjection extends CLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'vision_model',\n    });\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// SigLIP models\nexport class SiglipPreTrainedModel extends PreTrainedModel { }\n\n/**\n * SigLIP Text and Vision Model with a projection layers on top\n *\n * **Example:** Perform zero-shot image classification with a `SiglipModel`.\n *\n * ```javascript\n * import { AutoTokenizer, AutoProcessor, SiglipModel, RawImage } from '@huggingface/transformers';\n *\n * // Load tokenizer, processor, and model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/siglip-base-patch16-224');\n * const processor = await AutoProcessor.from_pretrained('Xenova/siglip-base-patch16-224');\n * const model = await SiglipModel.from_pretrained('Xenova/siglip-base-patch16-224');\n *\n * // Run tokenization\n * const texts = ['a photo of 2 cats', 'a photo of 2 dogs'];\n * const text_inputs = tokenizer(texts, { padding: 'max_length', truncation: true });\n *\n * // Read image and run processor\n * const image = await RawImage.read('http://images.cocodataset.org/val2017/000000039769.jpg');\n * const image_inputs = await processor(image);\n *\n * // Run model with both text and pixel inputs\n * const output = await model({ ...text_inputs, ...image_inputs });\n * // {\n * //   logits_per_image: Tensor {\n * //     dims: [ 1, 2 ],\n * //     data: Float32Array(2) [ -1.6019744873046875, -10.720091819763184 ],\n * //   },\n * //   logits_per_text: Tensor {\n * //     dims: [ 2, 1 ],\n * //     data: Float32Array(2) [ -1.6019744873046875, -10.720091819763184 ],\n * //   },\n * //   text_embeds: Tensor {\n * //     dims: [ 2, 768 ],\n * //     data: Float32Array(1536) [ ... ],\n * //   },\n * //   image_embeds: Tensor {\n * //     dims: [ 1, 768 ],\n * //     data: Float32Array(768) [ ... ],\n * //   }\n * // }\n * ```\n */\nexport class SiglipModel extends SiglipPreTrainedModel { }\n\n/**\n * The text model from SigLIP without any head or projection on top.\n *\n * **Example:** Compute text embeddings with `SiglipTextModel`.\n *\n * ```javascript\n * import { AutoTokenizer, SiglipTextModel } from '@huggingface/transformers';\n *\n * // Load tokenizer and text model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/siglip-base-patch16-224');\n * const text_model = await SiglipTextModel.from_pretrained('Xenova/siglip-base-patch16-224');\n *\n * // Run tokenization\n * const texts = ['a photo of 2 cats', 'a photo of 2 dogs'];\n * const text_inputs = tokenizer(texts, { padding: 'max_length', truncation: true });\n *\n * // Compute embeddings\n * const { pooler_output } = await text_model(text_inputs);\n * // Tensor {\n * //   dims: [ 2, 768 ],\n * //   type: 'float32',\n * //   data: Float32Array(1536) [ ... ],\n * //   size: 1536\n * // }\n * ```\n */\nexport class SiglipTextModel extends SiglipPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'text_model',\n    });\n  }\n}\n\n/**\n * The vision model from SigLIP without any head or projection on top.\n *\n * **Example:** Compute vision embeddings with `SiglipVisionModel`.\n *\n * ```javascript\n * import { AutoProcessor, SiglipVisionModel, RawImage} from '@huggingface/transformers';\n *\n * // Load processor and vision model\n * const processor = await AutoProcessor.from_pretrained('Xenova/siglip-base-patch16-224');\n * const vision_model = await SiglipVisionModel.from_pretrained('Xenova/siglip-base-patch16-224');\n *\n * // Read image and run processor\n * const image = await RawImage.read('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg');\n * const image_inputs = await processor(image);\n *\n * // Compute embeddings\n * const { pooler_output } = await vision_model(image_inputs);\n * // Tensor {\n * //   dims: [ 1, 768 ],\n * //   type: 'float32',\n * //   data: Float32Array(768) [ ... ],\n * //   size: 768\n * // }\n * ```\n */\nexport class SiglipVisionModel extends CLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'vision_model',\n    });\n  }\n}\n//////////////////////////////////////////////////\n// ChineseCLIP models\nexport class ChineseCLIPPreTrainedModel extends PreTrainedModel { }\n\nexport class ChineseCLIPModel extends ChineseCLIPPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// JinaCLIP models\nexport class JinaCLIPPreTrainedModel extends PreTrainedModel { }\n\nexport class JinaCLIPModel extends JinaCLIPPreTrainedModel {\n  async forward(model_inputs: any) {\n    const missing_text_inputs = !model_inputs.input_ids;\n    const missing_image_inputs = !model_inputs.pixel_values;\n\n    if (missing_text_inputs && missing_image_inputs) {\n      throw new Error('Either `input_ids` or `pixel_values` should be provided.');\n    }\n\n    // If either `input_ids` or `pixel_values` aren't passed, we need to create dummy input since the model requires a value to be specified.\n    if (missing_text_inputs) {\n      // NOTE: We cannot pass zero-dimension tensor as input for input_ids.\n      // Fortunately, the majority of time is spent in the vision encoder, so this shouldn't significantly impact performance.\n      model_inputs.input_ids = ones([model_inputs.pixel_values.dims[0], 1]);\n    }\n\n    if (missing_image_inputs) {\n      // NOTE: Since we create a zero-sized tensor, this does not increase computation time.\n      // @ts-ignore\n      const { image_size } = this.config.vision_config;\n      model_inputs.pixel_values = full([0, 3, image_size, image_size], 0.0); // (pass zero-dimension tensor)\n    }\n\n    const { text_embeddings, image_embeddings, l2norm_text_embeddings, l2norm_image_embeddings } = await super.forward(\n      model_inputs,\n    );\n\n    const result: any = {};\n    if (!missing_text_inputs) {\n      result.text_embeddings = text_embeddings;\n      result.l2norm_text_embeddings = l2norm_text_embeddings;\n    }\n    if (!missing_image_inputs) {\n      result.image_embeddings = image_embeddings;\n      result.l2norm_image_embeddings = l2norm_image_embeddings;\n    }\n    return result;\n  }\n}\n\nexport class JinaCLIPTextModel extends JinaCLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'text_model',\n    });\n  }\n}\n\nexport class JinaCLIPVisionModel extends JinaCLIPPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'vision_model',\n    });\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// GPT2 models\nexport class GPT2PreTrainedModel extends PreTrainedModel { }\n\nexport class GPT2Model extends GPT2PreTrainedModel { }\n\n/**\n * GPT-2 language model head on top of the GPT-2 base model. This model is suitable for text generation tasks.\n */\nexport class GPT2LMHeadModel extends GPT2PreTrainedModel { }\n// export class GPT2ForSequenceClassification extends GPT2PreTrainedModel {\n// TODO\n// }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// JAIS models\nexport class JAISPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare JAIS Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class JAISModel extends JAISPreTrainedModel { }\n\n/**\n * The JAIS Model transformer with a language modeling head on top (linear layer with weights tied to the input embeddings).\n */\nexport class JAISLMHeadModel extends JAISPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// GPTNeo models\nexport class GPTNeoPreTrainedModel extends PreTrainedModel { }\nexport class GPTNeoModel extends GPTNeoPreTrainedModel { }\n\nexport class GPTNeoForCausalLM extends GPTNeoPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// GPTNeoX models\nexport class GPTNeoXPreTrainedModel extends PreTrainedModel { }\nexport class GPTNeoXModel extends GPTNeoXPreTrainedModel { }\n\nexport class GPTNeoXForCausalLM extends GPTNeoXPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// GPT-J models\nexport class GPTJPreTrainedModel extends PreTrainedModel { }\n\nexport class GPTJModel extends GPTJPreTrainedModel { }\n\nexport class GPTJForCausalLM extends GPTJPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// GPTBigCode models\nexport class GPTBigCodePreTrainedModel extends PreTrainedModel { }\n\nexport class GPTBigCodeModel extends GPTBigCodePreTrainedModel { }\n\nexport class GPTBigCodeForCausalLM extends GPTBigCodePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// CodeGen models\nexport class CodeGenPreTrainedModel extends PreTrainedModel { }\n/**\n * CodeGenModel is a class representing a code generation model without a language model head.\n */\nexport class CodeGenModel extends CodeGenPreTrainedModel { }\n\n/**\n * CodeGenForCausalLM is a class that represents a code generation model based on the GPT-2 architecture. It extends the `CodeGenPreTrainedModel` class.\n */\nexport class CodeGenForCausalLM extends CodeGenPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// LLama models\n\n/**\n * The bare LLama Model outputting raw hidden-states without any specific head on top.\n */\nexport class LlamaPreTrainedModel extends PreTrainedModel { }\n/**\n * The bare LLaMA Model outputting raw hidden-states without any specific head on top.\n */\nexport class LlamaModel extends LlamaPreTrainedModel { }\n\nexport class LlamaForCausalLM extends LlamaPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// EXAONE models\nexport class ExaonePreTrainedModel extends PreTrainedModel { }\nexport class ExaoneModel extends ExaonePreTrainedModel { }\nexport class ExaoneForCausalLM extends ExaonePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// MobileLLM models\nexport class MobileLLMPreTrainedModel extends PreTrainedModel { }\nexport class MobileLLMModel extends MobileLLMPreTrainedModel { }\nexport class MobileLLMForCausalLM extends MobileLLMPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// OLMo models\nexport class OlmoPreTrainedModel extends PreTrainedModel { }\nexport class OlmoModel extends OlmoPreTrainedModel { }\nexport class OlmoForCausalLM extends OlmoPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// OLMo2 models\nexport class Olmo2PreTrainedModel extends PreTrainedModel { }\nexport class Olmo2Model extends Olmo2PreTrainedModel { }\nexport class Olmo2ForCausalLM extends Olmo2PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Granite models\nexport class GranitePreTrainedModel extends PreTrainedModel { }\nexport class GraniteModel extends GranitePreTrainedModel { }\nexport class GraniteForCausalLM extends GranitePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Cohere models\n\n/**\n * The bare Cohere Model outputting raw hidden-states without any specific head on top.\n */\nexport class CoherePreTrainedModel extends PreTrainedModel { }\nexport class CohereModel extends CoherePreTrainedModel { }\n\nexport class CohereForCausalLM extends CoherePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Gemma models\n\n/**\n * The bare Gemma Model outputting raw hidden-states without any specific head on top.\n */\nexport class GemmaPreTrainedModel extends PreTrainedModel { }\n/**\n * The bare Gemma Model outputting raw hidden-states without any specific head on top.\n */\nexport class GemmaModel extends GemmaPreTrainedModel { }\n\nexport class GemmaForCausalLM extends GemmaPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Gemma2 models\n\n/**\n * The bare Gemma2 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Gemma2PreTrainedModel extends PreTrainedModel { }\n/**\n * The bare Gemma2 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Gemma2Model extends Gemma2PreTrainedModel { }\n\nexport class Gemma2ForCausalLM extends Gemma2PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class OpenELMPreTrainedModel extends PreTrainedModel { }\nexport class OpenELMModel extends OpenELMPreTrainedModel { }\n\nexport class OpenELMForCausalLM extends OpenELMPreTrainedModel { }\n\n//////////////////////////////////////////////////\n// Qwen2 models\n\n/**\n * The bare Qwen2 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Qwen2PreTrainedModel extends PreTrainedModel { }\n/**\n * The bare Qwen2 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Qwen2Model extends Qwen2PreTrainedModel { }\n\nexport class Qwen2ForCausalLM extends Qwen2PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Phi models\nexport class PhiPreTrainedModel extends PreTrainedModel { }\n/**\n * The bare Phi Model outputting raw hidden-states without any specific head on top.\n */\nexport class PhiModel extends PhiPreTrainedModel { }\n\nexport class PhiForCausalLM extends PhiPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Phi3 models\nexport class Phi3PreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Phi3 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Phi3Model extends Phi3PreTrainedModel { }\n\nexport class Phi3ForCausalLM extends Phi3PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Bloom models\n/**\n * The Bloom Model transformer with a language modeling head on top (linear layer with weights tied to the input embeddings).\n */\nexport class BloomPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Bloom Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class BloomModel extends BloomPreTrainedModel { }\n\n/**\n * The Bloom Model transformer with a language modeling head on top (linear layer with weights tied to the input embeddings).\n */\nexport class BloomForCausalLM extends BloomPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// MPT models\nexport class MptPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Mpt Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class MptModel extends MptPreTrainedModel { }\n\n/**\n * The MPT Model transformer with a language modeling head on top (linear layer with weights tied to the input embeddings).\n */\nexport class MptForCausalLM extends MptPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// OPT models\nexport class OPTPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare OPT Model outputting raw hidden-states without any specific head on top.\n */\nexport class OPTModel extends OPTPreTrainedModel { }\n\n/**\n * The OPT Model transformer with a language modeling head on top (linear layer with weights tied to the input embeddings).\n */\nexport class OPTForCausalLM extends OPTPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class VitPosePreTrainedModel extends PreTrainedModel { }\n\n/**\n * The VitPose model with a pose estimation head on top.\n */\nexport class VitPoseForPoseEstimation extends VitPosePreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class ViTMAEPreTrainedModel extends PreTrainedModel { }\nexport class ViTMAEModel extends ViTMAEPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class GroupViTPreTrainedModel extends PreTrainedModel { }\nexport class GroupViTModel extends GroupViTPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class VitMattePreTrainedModel extends PreTrainedModel { }\n\n/**\n * ViTMatte framework leveraging any vision backbone e.g. for ADE20k, CityScapes.\n *\n * **Example:** Perform image matting with a `VitMatteForImageMatting` model.\n * ```javascript\n * import { AutoProcessor, VitMatteForImageMatting, RawImage } from '@huggingface/transformers';\n *\n * // Load processor and model\n * const processor = await AutoProcessor.from_pretrained('Xenova/vitmatte-small-distinctions-646');\n * const model = await VitMatteForImageMatting.from_pretrained('Xenova/vitmatte-small-distinctions-646');\n *\n * // Load image and trimap\n * const image = await RawImage.fromURL('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/vitmatte_image.png');\n * const trimap = await RawImage.fromURL('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/vitmatte_trimap.png');\n *\n * // Prepare image + trimap for the model\n * const inputs = await processor(image, trimap);\n *\n * // Predict alpha matte\n * const { alphas } = await model(inputs);\n * // Tensor {\n * //   dims: [ 1, 1, 640, 960 ],\n * //   type: 'float32',\n * //   size: 614400,\n * //   data: Float32Array(614400) [ 0.9894027709960938, 0.9970508813858032, ... ]\n * // }\n * ```\n *\n * You can visualize the alpha matte as follows:\n * ```javascript\n * import { Tensor, cat } from '@huggingface/transformers';\n *\n * // Visualize predicted alpha matte\n * const imageTensor = image.toTensor();\n *\n * // Convert float (0-1) alpha matte to uint8 (0-255)\n * const alphaChannel = alphas\n *   .squeeze(0)\n *   .mul_(255)\n *   .clamp_(0, 255)\n *   .round_()\n *   .to('uint8');\n *\n * // Concatenate original image with predicted alpha\n * const imageData = cat([imageTensor, alphaChannel], 0);\n *\n * // Save output image\n * const outputImage = RawImage.fromTensor(imageData);\n * outputImage.save('output.png');\n * ```\n */\nexport class VitMatteForImageMatting extends VitMattePreTrainedModel {\n  /**\n   * @param {any} model_inputs\n   */\n  async _call(model_inputs: any) {\n    return new ImageMattingOutput(await super._call(model_inputs));\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class Swin2SRPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Swin2SR Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class Swin2SRModel extends Swin2SRPreTrainedModel { }\n\n/**\n * Swin2SR Model transformer with an upsampler head on top for image super resolution and restoration.\n *\n * **Example:** Super-resolution w/ `Xenova/swin2SR-classical-sr-x2-64`.\n *\n * ```javascript\n * import { AutoProcessor, Swin2SRForImageSuperResolution, RawImage } from '@huggingface/transformers';\n *\n * // Load processor and model\n * const model_id = 'Xenova/swin2SR-classical-sr-x2-64';\n * const processor = await AutoProcessor.from_pretrained(model_id);\n * const model = await Swin2SRForImageSuperResolution.from_pretrained(model_id);\n *\n * // Prepare model inputs\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/butterfly.jpg';\n * const image = await RawImage.fromURL(url);\n * const inputs = await processor(image);\n *\n * // Run model\n * const outputs = await model(inputs);\n *\n * // Convert Tensor to RawImage\n * const output = outputs.reconstruction.squeeze().clamp_(0, 1).mul_(255).round_().to('uint8');\n * const outputImage = RawImage.fromTensor(output);\n * // RawImage {\n * //   data: Uint8Array(786432) [ 41, 31, 24, ... ],\n * //   width: 512,\n * //   height: 512,\n * //   channels: 3\n * // }\n * ```\n */\nexport class Swin2SRForImageSuperResolution extends Swin2SRPreTrainedModel { }\n//////////////////////////////////////////////////\n\n\n//////////////////////////////////////////////////\nexport class SamPreTrainedModel extends PreTrainedModel { }\n\n/**\n * Segment Anything Model (SAM) for generating segmentation masks, given an input image\n * and optional 2D location and bounding boxes.\n *\n * **Example:** Perform mask generation w/ `Xenova/sam-vit-base`.\n * ```javascript\n * import { SamModel, AutoProcessor, RawImage } from '@huggingface/transformers';\n *\n * const model = await SamModel.from_pretrained('Xenova/sam-vit-base');\n * const processor = await AutoProcessor.from_pretrained('Xenova/sam-vit-base');\n *\n * const img_url = 'https://huggingface.co/ybelkada/segment-anything/resolve/main/assets/car.png';\n * const raw_image = await RawImage.read(img_url);\n * const input_points = [[[450, 600]]] // 2D localization of a window\n *\n * const inputs = await processor(raw_image, { input_points });\n * const outputs = await model(inputs);\n *\n * const masks = await processor.post_process_masks(outputs.pred_masks, inputs.original_sizes, inputs.reshaped_input_sizes);\n * // [\n * //   Tensor {\n * //     dims: [ 1, 3, 1764, 2646 ],\n * //     type: 'bool',\n * //     data: Uint8Array(14002632) [ ... ],\n * //     size: 14002632\n * //   }\n * // ]\n * const scores = outputs.iou_scores;\n * // Tensor {\n * //   dims: [ 1, 1, 3 ],\n * //   type: 'float32',\n * //   data: Float32Array(3) [\n * //     0.8892380595207214,\n * //     0.9311248064041138,\n * //     0.983696699142456\n * //   ],\n * //   size: 3\n * // }\n * ```\n */\nexport class SamModel extends SamPreTrainedModel {\n  /**\n   * Compute image embeddings and positional image embeddings, given the pixel values of an image.\n   * @param {Object} model_inputs Object containing the model inputs.\n   * @param {Tensor} model_inputs.pixel_values Pixel values obtained using a `SamProcessor`.\n   * @returns {Promise<{ image_embeddings: Tensor, image_positional_embeddings: Tensor }>} The image embeddings and positional image embeddings.\n   */\n  async get_image_embeddings({ pixel_values }: { pixel_values: Tensor }) {\n    // in:\n    //  - pixel_values: tensor.float32[batch_size,3,1024,1024]\n    //\n    // out:\n    //  - image_embeddings: tensor.float32[batch_size,256,64,64]\n    //  - image_positional_embeddings: tensor.float32[batch_size,256,64,64]\n    return await encoderForward(this, { pixel_values });\n  }\n\n  /**\n   * @typedef {Object} SamModelInputs Object containing the model inputs.\n   * @property {Tensor} pixel_values Pixel values as a Tensor with shape `(batch_size, num_channels, height, width)`.\n   * These can be obtained using a `SamProcessor`.\n   * @property {Tensor} [input_points] Input 2D spatial points with shape `(batch_size, num_points, 2)`.\n   * This is used by the prompt encoder to encode the prompt.\n   * @property {Tensor} [input_labels] Input labels for the points, as a Tensor of shape `(batch_size, point_batch_size, num_points)`.\n   * This is used by the prompt encoder to encode the prompt. There are 4 types of labels:\n   *  - `1`: the point is a point that contains the object of interest\n   *  - `0`: the point is a point that does not contain the object of interest\n   *  - `-1`: the point corresponds to the background\n   *  - `-10`: the point is a padding point, thus should be ignored by the prompt encoder\n   * @property {Tensor} [input_boxes] Input bounding boxes with shape `(batch_size, num_boxes, 4)`.\n   * @property {Tensor} [image_embeddings] Image embeddings used by the mask decoder.\n   * @property {Tensor} [image_positional_embeddings] Image positional embeddings used by the mask decoder.\n   */\n\n  /**\n   * @param {SamModelInputs} model_inputs Object containing the model inputs.\n   * @returns {Promise<Object>} The output of the model.\n   */\n  async forward(model_inputs: any) {\n    if (!model_inputs.image_embeddings || !model_inputs.image_positional_embeddings) {\n      // Compute the image embeddings if they are missing\n      model_inputs = {\n        ...model_inputs,\n        ...(await this.get_image_embeddings(model_inputs)),\n      };\n    }\n\n    if (!model_inputs.input_labels && model_inputs.input_points) {\n      // Set default input labels if they are missing\n      const shape = (model_inputs.input_points as any).dims.slice(0, -1);\n      const numElements = shape.reduce((a: number, b: number) => a * b, 1);\n      model_inputs.input_labels = new Tensor('int64', new BigInt64Array(numElements).fill(1n), shape);\n    }\n\n    const decoder_inputs = {\n      image_embeddings: model_inputs.image_embeddings,\n      image_positional_embeddings: model_inputs.image_positional_embeddings,\n      input_points: null,\n      input_labels: null,\n      input_boxes: null,\n    };\n    if (model_inputs.input_points) {\n      decoder_inputs.input_points = model_inputs.input_points;\n    }\n    if (model_inputs.input_labels) {\n      decoder_inputs.input_labels = model_inputs.input_labels;\n    }\n    if (model_inputs.input_boxes) {\n      decoder_inputs.input_boxes = model_inputs.input_boxes;\n    }\n\n    // Returns:\n    //  - iou_scores: tensor.float32[batch_size,point_batch_size,3]\n    //  - pred_masks: tensor.float32[batch_size,point_batch_size,3,256,256]\n    return await sessionRun(this.sessions['prompt_encoder_mask_decoder'], decoder_inputs);\n  }\n\n  /**\n   * Runs the model with the provided inputs\n   * @param {Object} model_inputs Model inputs\n   * @returns {Promise<SamImageSegmentationOutput>} Object containing segmentation outputs\n   */\n  async _call(model_inputs: any) {\n    return new SamImageSegmentationOutput(await super._call(model_inputs));\n  }\n}\n\n/**\n * Base class for Segment-Anything model's output.\n */\nexport class SamImageSegmentationOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.iou_scores The output logits of the model.\n   * @param {Tensor} output.pred_masks Predicted boxes.\n   */\n  iou_scores: Tensor;\n  pred_masks: Tensor;\n  constructor({ iou_scores, pred_masks }: { iou_scores: Tensor; pred_masks: Tensor }) {\n    super();\n    this.iou_scores = iou_scores;\n    this.pred_masks = pred_masks;\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Wav2Vec2 models\nexport class Wav2Vec2PreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Wav2Vec2 Model transformer outputting raw hidden-states without any specific head on top.\n *\n * **Example:** Load and run a `Wav2Vec2Model` for feature extraction.\n *\n * ```javascript\n * import { AutoProcessor, AutoModel, read_audio } from '@huggingface/transformers';\n *\n * // Read and preprocess audio\n * const processor = await AutoProcessor.from_pretrained('Xenova/mms-300m');\n * const audio = await read_audio('https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac', 16000);\n * const inputs = await processor(audio);\n *\n * // Run model with inputs\n * const model = await AutoModel.from_pretrained('Xenova/mms-300m');\n * const output = await model(inputs);\n * // {\n * //   last_hidden_state: Tensor {\n * //     dims: [ 1, 1144, 1024 ],\n * //     type: 'float32',\n * //     data: Float32Array(1171456) [ ... ],\n * //     size: 1171456\n * //   }\n * // }\n * ```\n */\nexport class Wav2Vec2Model extends Wav2Vec2PreTrainedModel { }\n\nexport class Wav2Vec2ForCTC extends Wav2Vec2PreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_values Float values of input raw speech waveform.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// PyAnnote models\nexport class PyAnnotePreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare PyAnnote Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class PyAnnoteModel extends PyAnnotePreTrainedModel { }\n\n/**\n * PyAnnote Model with a frame classification head on top for tasks like Speaker Diarization.\n *\n * **Example:** Load and run a `PyAnnoteForAudioFrameClassification` for speaker diarization.\n *\n * ```javascript\n * import { AutoProcessor, AutoModelForAudioFrameClassification, read_audio } from '@huggingface/transformers';\n *\n * // Load model and processor\n * const model_id = 'onnx-community/pyannote-segmentation-3.0';\n * const model = await AutoModelForAudioFrameClassification.from_pretrained(model_id);\n * const processor = await AutoProcessor.from_pretrained(model_id);\n *\n * // Read and preprocess audio\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/mlk.wav';\n * const audio = await read_audio(url, processor.feature_extractor.config.sampling_rate);\n * const inputs = await processor(audio);\n *\n * // Run model with inputs\n * const { logits } = await model(inputs);\n * // {\n * //   logits: Tensor {\n * //     dims: [ 1, 767, 7 ],  // [batch_size, num_frames, num_classes]\n * //     type: 'float32',\n * //     data: Float32Array(5369) [ ... ],\n * //     size: 5369\n * //   }\n * // }\n *\n * const result = processor.post_process_speaker_diarization(logits, audio.length);\n * // [\n * //   [\n * //     { id: 0, start: 0, end: 1.0512535626298245, confidence: 0.8220156481664611 },\n * //     { id: 2, start: 1.0512535626298245, end: 2.3398869619825127, confidence: 0.9008811707860472 },\n * //     ...\n * //   ]\n * // ]\n *\n * // Display result\n * console.table(result[0], ['start', 'end', 'id', 'confidence']);\n * // ┌─────────┬────────────────────┬────────────────────┬────┬─────────────────────┐\n * // │ (index) │ start              │ end                │ id │ confidence          │\n * // ├─────────┼────────────────────┼────────────────────┼────┼─────────────────────┤\n * // │ 0       │ 0                  │ 1.0512535626298245 │ 0  │ 0.8220156481664611  │\n * // │ 1       │ 1.0512535626298245 │ 2.3398869619825127 │ 2  │ 0.9008811707860472  │\n * // │ 2       │ 2.3398869619825127 │ 3.5946089560890773 │ 0  │ 0.7521651315796233  │\n * // │ 3       │ 3.5946089560890773 │ 4.578039708226655  │ 2  │ 0.8491978128022479  │\n * // │ 4       │ 4.578039708226655  │ 4.594995410849717  │ 0  │ 0.2935352600416393  │\n * // │ 5       │ 4.594995410849717  │ 6.121008646925269  │ 3  │ 0.6788051309866024  │\n * // │ 6       │ 6.121008646925269  │ 6.256654267909762  │ 0  │ 0.37125512393851134 │\n * // │ 7       │ 6.256654267909762  │ 8.630452635138397  │ 2  │ 0.7467035186353542  │\n * // │ 8       │ 8.630452635138397  │ 10.088643060721703 │ 0  │ 0.7689364814666032  │\n * // │ 9       │ 10.088643060721703 │ 12.58113134631177  │ 2  │ 0.9123324509131324  │\n * // │ 10      │ 12.58113134631177  │ 13.005023911888312 │ 0  │ 0.4828358177572041  │\n * // └─────────┴────────────────────┴────────────────────┴────┴─────────────────────┘\n * ```\n */\nexport class PyAnnoteForAudioFrameClassification extends PyAnnotePreTrainedModel {\n  /**\n   * Calls the model on new inputs.\n   * @param {Object} model_inputs The inputs to the model.\n   * @returns {Promise<TokenClassifierOutput>} An object containing the model's output logits for sequence classification.\n   */\n  async _call(model_inputs: any) {\n    return new TokenClassifierOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// WeSpeakerResNet models\nexport class WeSpeakerResNetPreTrainedModel extends PreTrainedModel { }\nexport class WeSpeakerResNetModel extends WeSpeakerResNetPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// UniSpeech models\nexport class UniSpeechPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare UniSpeech Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class UniSpeechModel extends UniSpeechPreTrainedModel { }\n\n/**\n * UniSpeech Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).\n */\nexport class UniSpeechForCTC extends UniSpeechPreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_values Float values of input raw speech waveform.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// UniSpeechSat models\nexport class UniSpeechSatPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare UniSpeechSat Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class UniSpeechSatModel extends UniSpeechSatPreTrainedModel { }\n\n/**\n * UniSpeechSat Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).\n */\nexport class UniSpeechSatForCTC extends UniSpeechSatPreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_values Float values of input raw speech waveform.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n/**\n * UniSpeechSat Model with a frame classification head on top for tasks like Speaker Diarization.\n */\nexport class UniSpeechSatForAudioFrameClassification extends UniSpeechSatPreTrainedModel {\n  /**\n   * Calls the model on new inputs.\n   * @param {Object} model_inputs The inputs to the model.\n   * @returns {Promise<TokenClassifierOutput>} An object containing the model's output logits for sequence classification.\n   */\n  async _call(model_inputs: any) {\n    return new TokenClassifierOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Wav2Vec2Bert models\nexport class Wav2Vec2BertPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Wav2Vec2Bert Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class Wav2Vec2BertModel extends Wav2Vec2BertPreTrainedModel { }\n\n/**\n * Wav2Vec2Bert Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).\n */\nexport class Wav2Vec2BertForCTC extends Wav2Vec2BertPreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_features Float values of input mel-spectrogram.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Hubert models\nexport class HubertPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Hubert Model transformer outputting raw hidden-states without any specific head on top.\n *\n * **Example:** Load and run a `HubertModel` for feature extraction.\n *\n * ```javascript\n * import { AutoProcessor, AutoModel, read_audio } from '@huggingface/transformers';\n *\n * // Read and preprocess audio\n * const processor = await AutoProcessor.from_pretrained('Xenova/hubert-base-ls960');\n * const audio = await read_audio('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav', 16000);\n * const inputs = await processor(audio);\n *\n * // Load and run model with inputs\n * const model = await AutoModel.from_pretrained('Xenova/hubert-base-ls960');\n * const output = await model(inputs);\n * // {\n * //   last_hidden_state: Tensor {\n * //     dims: [ 1, 549, 768 ],\n * //     type: 'float32',\n * //     data: Float32Array(421632) [0.0682469978928566, 0.08104046434164047, -0.4975186586380005, ...],\n * //     size: 421632\n * //   }\n * // }\n * ```\n */\nexport class HubertModel extends Wav2Vec2PreTrainedModel { }\n\n/**\n * Hubert Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).\n */\nexport class HubertForCTC extends Wav2Vec2PreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_values Float values of input raw speech waveform.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// WavLM models\n/**\n * An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained models.\n */\nexport class WavLMPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare WavLM Model transformer outputting raw hidden-states without any specific head on top.\n *\n * **Example:** Load and run a `WavLMModel` for feature extraction.\n *\n * ```javascript\n * import { AutoProcessor, AutoModel, read_audio } from '@huggingface/transformers';\n *\n * // Read and preprocess audio\n * const processor = await AutoProcessor.from_pretrained('Xenova/wavlm-base');\n * const audio = await read_audio('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav', 16000);\n * const inputs = await processor(audio);\n *\n * // Run model with inputs\n * const model = await AutoModel.from_pretrained('Xenova/wavlm-base');\n * const output = await model(inputs);\n * // {\n * //   last_hidden_state: Tensor {\n * //     dims: [ 1, 549, 768 ],\n * //     type: 'float32',\n * //     data: Float32Array(421632) [-0.349443256855011, -0.39341306686401367,  0.022836603224277496, ...],\n * //     size: 421632\n * //   }\n * // }\n * ```\n */\nexport class WavLMModel extends WavLMPreTrainedModel { }\n\n/**\n * WavLM Model with a `language modeling` head on top for Connectionist Temporal Classification (CTC).\n */\nexport class WavLMForCTC extends WavLMPreTrainedModel {\n  /**\n   * @param {Object} model_inputs\n   * @param {Tensor} model_inputs.input_values Float values of input raw speech waveform.\n   * @param {Tensor} model_inputs.attention_mask Mask to avoid performing convolution and attention on padding token indices. Mask values selected in [0, 1]\n   */\n  async _call(model_inputs: any) {\n    return new CausalLMOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n/**\n * WavLM Model with an XVector feature extraction head on top for tasks like Speaker Verification.\n *\n * **Example:** Extract speaker embeddings with `WavLMForXVector`.\n * ```javascript\n * import { AutoProcessor, AutoModel, read_audio } from '@huggingface/transformers';\n *\n * // Read and preprocess audio\n * const processor = await AutoProcessor.from_pretrained('Xenova/wavlm-base-plus-sv');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav';\n * const audio = await read_audio(url, 16000);\n * const inputs = await processor(audio);\n *\n * // Run model with inputs\n * const model = await AutoModel.from_pretrained('Xenova/wavlm-base-plus-sv');\n * const outputs = await model(inputs);\n * // {\n * //   logits: Tensor {\n * //     dims: [ 1, 512 ],\n * //     type: 'float32',\n * //     data: Float32Array(512) [0.5847219228744507, ...],\n * //     size: 512\n * //   },\n * //   embeddings: Tensor {\n * //     dims: [ 1, 512 ],\n * //     type: 'float32',\n * //     data: Float32Array(512) [-0.09079201519489288, ...],\n * //     size: 512\n * //   }\n * // }\n * ```\n */\nexport class WavLMForXVector extends WavLMPreTrainedModel {\n  /**\n   * Calls the model on new inputs.\n   * @param {Object} model_inputs The inputs to the model.\n   * @returns {Promise<XVectorOutput>} An object containing the model's output logits and speaker embeddings.\n   */\n  async _call(model_inputs: any) {\n    return new XVectorOutput(await super._call(model_inputs) as { logits: Tensor, embeddings: Tensor });\n  }\n}\n\n/**\n * WavLM Model with a frame classification head on top for tasks like Speaker Diarization.\n *\n * **Example:** Perform speaker diarization with `WavLMForAudioFrameClassification`.\n * ```javascript\n * import { AutoProcessor, AutoModelForAudioFrameClassification, read_audio } from '@huggingface/transformers';\n *\n * // Read and preprocess audio\n * const processor = await AutoProcessor.from_pretrained('Xenova/wavlm-base-plus-sd');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav';\n * const audio = await read_audio(url, 16000);\n * const inputs = await processor(audio);\n *\n * // Run model with inputs\n * const model = await AutoModelForAudioFrameClassification.from_pretrained('Xenova/wavlm-base-plus-sd');\n * const { logits } = await model(inputs);\n * // {\n * //   logits: Tensor {\n * //     dims: [ 1, 549, 2 ],  // [batch_size, num_frames, num_speakers]\n * //     type: 'float32',\n * //     data: Float32Array(1098) [-3.5301010608673096, ...],\n * //     size: 1098\n * //   }\n * // }\n *\n * const labels = logits[0].sigmoid().tolist().map(\n *     frames => frames.map(speaker => speaker > 0.5 ? 1 : 0)\n * );\n * console.log(labels); // labels is a one-hot array of shape (num_frames, num_speakers)\n * // [\n * //     [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],\n * //     [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],\n * //     [0, 0], [0, 1], [0, 1], [0, 1], [0, 1], [0, 1],\n * //     ...\n * // ]\n * ```\n */\nexport class WavLMForAudioFrameClassification extends WavLMPreTrainedModel {\n  /**\n   * Calls the model on new inputs.\n   * @param {Object} model_inputs The inputs to the model.\n   * @returns {Promise<TokenClassifierOutput>} An object containing the model's output logits for sequence classification.\n   */\n  async _call(model_inputs: any) {\n    return new TokenClassifierOutput(await super._call(model_inputs) as { logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n// SpeechT5 models\n/**\n * An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained models.\n */\nexport class SpeechT5PreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare SpeechT5 Encoder-Decoder Model outputting raw hidden-states without any specific pre- or post-nets.\n */\nexport class SpeechT5Model extends SpeechT5PreTrainedModel { }\n\n/**\n * SpeechT5 Model with a speech encoder and a text decoder.\n *\n * **Example:** Generate speech from text with `SpeechT5ForSpeechToText`.\n * ```javascript\n * import { AutoTokenizer, AutoProcessor, SpeechT5ForTextToSpeech, SpeechT5HifiGan, Tensor } from '@huggingface/transformers';\n *\n * // Load the tokenizer and processor\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/speecht5_tts');\n * const processor = await AutoProcessor.from_pretrained('Xenova/speecht5_tts');\n *\n * // Load the models\n * // NOTE: We use the full-precision versions as they are more accurate\n * const model = await SpeechT5ForTextToSpeech.from_pretrained('Xenova/speecht5_tts', { dtype: 'fp32' });\n * const vocoder = await SpeechT5HifiGan.from_pretrained('Xenova/speecht5_hifigan', { dtype: 'fp32' });\n *\n * // Load speaker embeddings from URL\n * const speaker_embeddings_data = new Float32Array(\n *     await (await fetch('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/speaker_embeddings.bin')).arrayBuffer()\n * );\n * const speaker_embeddings = new Tensor(\n *     'float32',\n *     speaker_embeddings_data,\n *     [1, speaker_embeddings_data.length]\n * )\n *\n * // Run tokenization\n * const { input_ids } = tokenizer('Hello, my dog is cute');\n *\n * // Generate waveform\n * const { waveform } = await model.generate_speech(input_ids, speaker_embeddings, { vocoder });\n * console.log(waveform)\n * // Tensor {\n * //   dims: [ 26112 ],\n * //   type: 'float32',\n * //   size: 26112,\n * //   data: Float32Array(26112) [ -0.00043630177970044315, -0.00018082228780258447, ... ],\n * // }\n * ```\n */\nexport class SpeechT5ForSpeechToText extends SpeechT5PreTrainedModel { }\n\n/**\n * SpeechT5 Model with a text encoder and a speech decoder.\n */\nexport class SpeechT5ForTextToSpeech extends SpeechT5PreTrainedModel {\n  /**\n   * @typedef {Object} SpeechOutput\n   * @property {Tensor} [spectrogram] The predicted log-mel spectrogram of shape\n   * `(output_sequence_length, config.num_mel_bins)`. Returned when no `vocoder` is provided\n   * @property {Tensor} [waveform] The predicted waveform of shape `(num_frames,)`. Returned when a `vocoder` is provided.\n   * @property {Tensor} [cross_attentions] The outputs of the decoder's cross-attention layers of shape\n   * `(config.decoder_layers, config.decoder_attention_heads, output_sequence_length, input_sequence_length)`. returned when `output_cross_attentions` is `true`.\n   */\n\n  /**\n   * Converts a sequence of input tokens into a sequence of mel spectrograms, which are subsequently turned into a speech waveform using a vocoder.\n   * @param {Tensor} input_values Indices of input sequence tokens in the vocabulary.\n   * @param {Tensor} speaker_embeddings Tensor containing the speaker embeddings.\n   * @param {Object} options Optional parameters for generating speech.\n   * @param {number} [options.threshold=0.5] The generated sequence ends when the predicted stop token probability exceeds this value.\n   * @param {number} [options.minlenratio=0.0] Used to calculate the minimum required length for the output sequence.\n   * @param {number} [options.maxlenratio=20.0] Used to calculate the maximum allowed length for the output sequence.\n   * @param {Object} [options.vocoder=null] The vocoder that converts the mel spectrogram into a speech waveform. If `null`, the output is the mel spectrogram.\n   * @param {boolean} [options.output_cross_attentions=false] Whether or not to return the attentions tensors of the decoder's cross-attention layers.\n   * @returns {Promise<SpeechOutput>} A promise which resolves to an object containing the spectrogram, waveform, and cross-attention tensors.\n   */\n  async generate_speech(\n    input_values: Tensor,\n    speaker_embeddings: Tensor,\n    {\n      threshold = 0.5,\n      minlenratio = 0.0,\n      maxlenratio = 20.0,\n      vocoder = null,\n      // output_cross_attentions = false, // TODO add\n    } = {},\n  ) {\n    const model_inputs = {\n      input_ids: input_values,\n    };\n\n    const { encoder_outputs, encoder_attention_mask } = await encoderForward(this, model_inputs);\n\n    // @ts-expect-error TS2339\n    const r = encoder_outputs.dims[1] / this.config.reduction_factor;\n    const maxlen = Math.floor(r * maxlenratio);\n    const minlen = Math.floor(r * minlenratio);\n\n    // @ts-expect-error TS2339\n    const num_mel_bins = this.config.num_mel_bins;\n\n    let spectrogramParts = [];\n    let past_key_values = null;\n    let decoder_outputs = null;\n    let idx = 0;\n\n    while (true) {\n      ++idx;\n\n      const use_cache_branch = boolTensor(!!decoder_outputs);\n      let output_sequence;\n      if (decoder_outputs) {\n        output_sequence = decoder_outputs.output_sequence_out;\n      } else {\n        output_sequence = new Tensor('float32', new Float32Array(num_mel_bins), [1, 1, num_mel_bins]);\n      }\n      let decoderFeeds = {\n        use_cache_branch,\n        output_sequence,\n        encoder_attention_mask: encoder_attention_mask,\n        speaker_embeddings: speaker_embeddings,\n        encoder_hidden_states: encoder_outputs,\n      };\n\n      this.addPastKeyValues(decoderFeeds, past_key_values);\n      decoder_outputs = await sessionRun(this.sessions['decoder_model_merged'], decoderFeeds);\n      past_key_values = this.getPastKeyValues(decoder_outputs, past_key_values);\n\n      const { prob, spectrum } = decoder_outputs;\n      spectrogramParts.push(spectrum);\n\n      if (\n        idx >= minlen &&\n        // Finished when stop token or maximum length is reached.\n        (Array.from(prob.data as Float32Array).filter((p) => p >= threshold).length > 0 || idx >= maxlen)\n      ) {\n        break;\n      }\n    }\n\n    const spectrogram = cat(spectrogramParts);\n    const { waveform } = await sessionRun((vocoder as any).sessions['model'], { spectrogram: spectrogram as any });\n\n    return {\n      spectrogram,\n      waveform,\n      // cross_attentions: null, // TODO add\n    };\n  }\n}\n\n/**\n * HiFi-GAN vocoder.\n *\n * See [SpeechT5ForSpeechToText](./models#module_models.SpeechT5ForSpeechToText) for example usage.\n */\nexport class SpeechT5HifiGan extends PreTrainedModel {\n  main_input_name = 'spectrogram';\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// TrOCR models\nexport class TrOCRPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The TrOCR Decoder with a language modeling head.\n */\nexport class TrOCRForCausalLM extends TrOCRPreTrainedModel { }\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Mistral models\n/**\n * The bare Mistral Model outputting raw hidden-states without any specific head on top.\n */\nexport class MistralPreTrainedModel extends PreTrainedModel { }\n\nexport class MistralModel extends MistralPreTrainedModel { }\n\nexport class MistralForCausalLM extends MistralPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Starcoder2 models\n/**\n * The bare Starcoder2 Model outputting raw hidden-states without any specific head on top.\n */\nexport class Starcoder2PreTrainedModel extends PreTrainedModel { }\n\nexport class Starcoder2Model extends Starcoder2PreTrainedModel { }\n\nexport class Starcoder2ForCausalLM extends Starcoder2PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Falcon models\n/**\n * The bare Falcon Model outputting raw hidden-states without any specific head on top.\n */\nexport class FalconPreTrainedModel extends PreTrainedModel { }\n\nexport class FalconModel extends FalconPreTrainedModel { }\n\nexport class FalconForCausalLM extends FalconPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// CLAP models\nexport class ClapPreTrainedModel extends PreTrainedModel { }\n\nexport class ClapModel extends ClapPreTrainedModel { }\n\n/**\n * CLAP Text Model with a projection layer on top (a linear layer on top of the pooled output).\n *\n * **Example:** Compute text embeddings with `ClapTextModelWithProjection`.\n *\n * ```javascript\n * import { AutoTokenizer, ClapTextModelWithProjection } from '@huggingface/transformers';\n *\n * // Load tokenizer and text model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/clap-htsat-unfused');\n * const text_model = await ClapTextModelWithProjection.from_pretrained('Xenova/clap-htsat-unfused');\n *\n * // Run tokenization\n * const texts = ['a sound of a cat', 'a sound of a dog'];\n * const text_inputs = tokenizer(texts, { padding: true, truncation: true });\n *\n * // Compute embeddings\n * const { text_embeds } = await text_model(text_inputs);\n * // Tensor {\n * //   dims: [ 2, 512 ],\n * //   type: 'float32',\n * //   data: Float32Array(1024) [ ... ],\n * //   size: 1024\n * // }\n * ```\n */\nexport class ClapTextModelWithProjection extends ClapPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'text_model',\n    });\n  }\n}\n\n/**\n * CLAP Audio Model with a projection layer on top (a linear layer on top of the pooled output).\n *\n * **Example:** Compute audio embeddings with `ClapAudioModelWithProjection`.\n *\n * ```javascript\n * import { AutoProcessor, ClapAudioModelWithProjection, read_audio } from '@huggingface/transformers';\n *\n * // Load processor and audio model\n * const processor = await AutoProcessor.from_pretrained('Xenova/clap-htsat-unfused');\n * const audio_model = await ClapAudioModelWithProjection.from_pretrained('Xenova/clap-htsat-unfused');\n *\n * // Read audio and run processor\n * const audio = await read_audio('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/cat_meow.wav');\n * const audio_inputs = await processor(audio);\n *\n * // Compute embeddings\n * const { audio_embeds } = await audio_model(audio_inputs);\n * // Tensor {\n * //   dims: [ 1, 512 ],\n * //   type: 'float32',\n * //   data: Float32Array(512) [ ... ],\n * //   size: 512\n * // }\n * ```\n */\nexport class ClapAudioModelWithProjection extends ClapPreTrainedModel {\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any = {}) {\n    return super.from_pretrained(pretrained_model_name_or_path, {\n      ...options,\n      // Update default model file name if not provided\n      model_file_name: options.model_file_name ?? 'audio_model',\n    });\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// VITS models\nexport class VitsPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The complete VITS model, for text-to-speech synthesis.\n *\n * **Example:** Generate speech from text with `VitsModel`.\n * ```javascript\n * import { AutoTokenizer, VitsModel } from '@huggingface/transformers';\n *\n * // Load the tokenizer and model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/mms-tts-eng');\n * const model = await VitsModel.from_pretrained('Xenova/mms-tts-eng');\n *\n * // Run tokenization\n * const inputs = tokenizer('I love transformers');\n *\n * // Generate waveform\n * const { waveform } = await model(inputs);\n * // Tensor {\n * //   dims: [ 1, 35328 ],\n * //   type: 'float32',\n * //   data: Float32Array(35328) [ ... ],\n * //   size: 35328,\n * // }\n * ```\n */\nexport class VitsModel extends VitsPreTrainedModel {\n  /**\n   * Calls the model on new inputs.\n   * @param {Object} model_inputs The inputs to the model.\n   * @returns {Promise<VitsModelOutput>} The outputs for the VITS model.\n   */\n  async _call(model_inputs: any) {\n    return new VitsModelOutput(await super._call(model_inputs) as VitsModelOutput);\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// StableLm models\nexport class StableLmPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare StableLm Model transformer outputting raw hidden-states without any specific head on top.\n */\nexport class StableLmModel extends StableLmPreTrainedModel { }\n\n/**\n * StableLm Model with a `language modeling` head on top for Causal Language Modeling (with past).\n */\nexport class StableLmForCausalLM extends StableLmPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Musicgen models\nexport class MusicgenPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare Musicgen decoder model outputting raw hidden-states without any specific head on top.\n */\nexport class MusicgenModel extends MusicgenPreTrainedModel { }\n\n/**\n * The MusicGen decoder model with a language modelling head on top.\n */\nexport class MusicgenForCausalLM extends MusicgenPreTrainedModel { }\n\n/**\n * The composite MusicGen model with a text encoder, audio encoder and Musicgen decoder,\n * for music generation tasks with one or both of text and audio prompts.\n *\n * **Example:** Generate music from text with `Xenova/musicgen-small`.\n * ```javascript\n * import { AutoTokenizer, MusicgenForConditionalGeneration } from '@huggingface/transformers';\n *\n * // Load tokenizer and model\n * const tokenizer = await AutoTokenizer.from_pretrained('Xenova/musicgen-small');\n * const model = await MusicgenForConditionalGeneration.from_pretrained(\n *   'Xenova/musicgen-small', { dtype: 'fp32' }\n * );\n *\n * // Prepare text input\n * const prompt = '80s pop track with bassy drums and synth';\n * const inputs = tokenizer(prompt);\n *\n * // Generate audio\n * const audio_values = await model.generate({\n *   ...inputs,\n *   max_new_tokens: 512,\n *   do_sample: true,\n *   guidance_scale: 3,\n * });\n *\n * // (Optional) Write the output to a WAV file\n * import wavefile from 'wavefile';\n * import fs from 'fs';\n *\n * const wav = new wavefile.WaveFile();\n * wav.fromScratch(1, model.config.audio_encoder.sampling_rate, '32f', audio_values.data);\n * fs.writeFileSync('musicgen_out.wav', wav.toBuffer());\n * ```\n */\nexport class MusicgenForConditionalGeneration extends PreTrainedModel {\n  // NOTE: not MusicgenPreTrainedModel\n  forward_params = [\n    'input_ids',\n    'attention_mask',\n    'encoder_outputs',\n    'decoder_input_ids',\n    'decoder_attention_mask',\n    'past_key_values',\n  ];\n\n  /**\n   * Apply the pattern mask to the final ids,\n   * then revert the pattern delay mask by filtering the pad token id in a single step.\n   * @param {Tensor} outputs The output tensor from the model.\n   * @returns {Tensor} The filtered output tensor.\n   */\n  _apply_and_filter_by_delay_pattern_mask(outputs: any) {\n    const [bs_x_codebooks, seqLength] = outputs.dims;\n    // @ts-expect-error TS2339\n    const num_codebooks = this.config.decoder.num_codebooks;\n    const upperBound = seqLength - num_codebooks;\n\n    let newDataSize = 0;\n    for (let i = 0; i < outputs.size; ++i) {\n      // @ts-expect-error TS2339\n      if (outputs.data[i] === this.config.decoder.pad_token_id) {\n        continue;\n      }\n\n      const row = i % seqLength;\n      const col = Math.floor(i / seqLength) % num_codebooks;\n\n      const diff = row - col;\n      if (diff > 0 && diff <= upperBound) {\n        outputs.data[newDataSize++] = outputs.data[i];\n      }\n    }\n\n    const batch_size = Math.floor(bs_x_codebooks / num_codebooks);\n    const inferred = newDataSize / (batch_size * num_codebooks);\n    // TODO: assert `inferred` is an integer\n    return new Tensor(outputs.type, outputs.data.slice(0, newDataSize), [batch_size, num_codebooks, inferred]);\n  }\n\n  prepare_inputs_for_generation(input_ids: any, model_inputs: any, generation_config: any) {\n    // apply the delay pattern mask\n    let clonedInputIds = structuredClone(input_ids);\n    for (let i = 0; i < clonedInputIds.length; ++i) {\n      for (let j = 0; j < clonedInputIds[i].length; ++j) {\n        // @ts-expect-error TS2339\n        if (i % this.config.decoder.num_codebooks >= j) {\n          // @ts-expect-error TS2339\n          clonedInputIds[i][j] = BigInt(this.config.decoder.pad_token_id);\n        }\n      }\n    }\n    // for classifier free guidance we need to replicate the decoder args across the batch dim\n    // (we'll split these before sampling)\n    if (generation_config.guidance_scale !== null && generation_config.guidance_scale > 1) {\n      // [batch, seqLength] -> [2 * batch, seqLength]\n      clonedInputIds = clonedInputIds.concat(clonedInputIds);\n    }\n\n    const prepped = super.prepare_inputs_for_generation(clonedInputIds, model_inputs, generation_config);\n    return prepped;\n  }\n\n  /**\n   * Generates sequences of token ids for models with a language modeling head.\n   * @param {import('./generation/parameters.js').GenerationFunctionParameters} options\n   * @returns {Promise<ModelOutput|Tensor>} The output of the model, which can contain the generated token ids, attentions, and scores.\n   */\n  async generate(options: any) {\n    const output_ids = await super.generate(options);\n\n    // apply the pattern mask to the final ids\n    // tensor: int64[1,batch_size,4,chunk_length]\n    const audio_codes = this._apply_and_filter_by_delay_pattern_mask(/** @type {Tensor} */ output_ids).unsqueeze_(0); // append the frame dimension back to the audio codes\n\n    const { audio_values } = await sessionRun(this.sessions['encodec_decode'], { audio_codes });\n\n    return audio_values;\n  }\n}\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// Decision Transformer models\nexport class DecisionTransformerPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The model builds upon the GPT2 architecture to perform autoregressive prediction of actions in an offline RL setting.\n * Refer to the paper for more details: https://arxiv.org/abs/2106.01345\n */\nexport class DecisionTransformerModel extends DecisionTransformerPreTrainedModel { }\n\n//////////////////////////////////////////////////\n\nexport class MultiModalityPreTrainedModel extends PreTrainedModel { }\nexport class MultiModalityCausalLM extends MultiModalityPreTrainedModel {\n  forward_params = [\n    // prepare_inputs_embeds\n    'input_ids',\n    'pixel_values',\n    'images_seq_mask',\n    'images_emb_mask',\n\n    // language_model\n    'attention_mask',\n    'position_ids',\n    'past_key_values',\n  ];\n\n  /**\n   * @param {ConstructorParameters<typeof MultiModalityPreTrainedModel>} args\n   */\n\n  _generation_mode: string;\n  sessions: any;\n  constructor(args: ConstructorParameters<typeof MultiModalityPreTrainedModel>[0]) {\n    super(args, {}, {});\n\n    // State-based approach to switch out which heads to use during generation\n    this._generation_mode = 'text';\n  }\n\n  async forward(model_inputs: any) {\n    const mode = this._generation_mode ?? 'text';\n\n    // TODO support re-using PKVs for input_ids.dims[1] !== 1\n    // if (model_inputs.past_key_values) {\n    //     //  && model_inputs.input_ids.dims[1] === 1\n    // }\n\n    let output_1;\n    if (mode === 'text' || !model_inputs.past_key_values) {\n      const session = this.sessions['prepare_inputs_embeds'];\n      const prep_inputs = pick(model_inputs, session.inputNames);\n      output_1 = await sessionRun(session, prep_inputs);\n    } else {\n      const session = this.sessions['gen_img_embeds'];\n      const prep_inputs = pick(\n        {\n          image_ids: model_inputs.input_ids,\n        },\n        session.inputNames,\n      );\n      output_1 = await sessionRun(session, prep_inputs);\n    }\n\n    const input_2 = { ...model_inputs, ...output_1 };\n    const output_2 = await decoderForward(this, input_2);\n\n    const head = this.sessions[mode === 'text' ? 'lm_head' : 'gen_head'];\n    if (!head) {\n      throw new Error(`Unable to find \"${head}\" generation head`);\n    }\n\n    const output_3 = await sessionRun(head, pick(output_2, head.inputNames));\n\n    return {\n      ...output_1,\n      ...output_2,\n      ...output_3,\n    };\n  }\n\n  /**\n   * @param {import('./generation/parameters.js').GenerationFunctionParameters} options\n   */\n  async generate(options: any) {\n    this._generation_mode = 'text';\n    return super.generate(options);\n  }\n\n  /**\n   * @param {import('./generation/parameters.js').GenerationFunctionParameters} options\n   */\n  async generate_images(options: any) {\n    this._generation_mode = 'image';\n\n    const start_num_tokens = (options.inputs ?? options[this.main_input_name]).dims[1];\n    const all_tokens = await super.generate(options);\n\n    const generated_tokens = /** @type {Tensor} */ ((all_tokens as Tensor).slice(null, [start_num_tokens, null]));\n\n    const image_decode = this.sessions['image_decode'];\n    const { decoded_image } = await sessionRun(image_decode, {\n      generated_tokens,\n    });\n\n    // Equivalent to `np.clip((dec + 1) / 2 * 255, 0, 255)`\n    const clamped = decoded_image\n      .add_(1)\n      .mul_(255 / 2)\n      .clamp_(0, 255)\n      .to('uint8');\n\n    // Return as a list of images\n    const images = [];\n    for (const tensor of clamped) {\n      const img = RawImage.fromTensor(tensor);\n      images.push(img);\n    }\n    return images;\n  }\n}\n\nexport class MgpstrModelOutput extends ModelOutput {\n  char_logits: Tensor;\n  bpe_logits: Tensor;\n  wp_logits: Tensor;\n  constructor({ char_logits, bpe_logits, wp_logits }: any) {\n    super();\n    this.char_logits = char_logits;\n    this.bpe_logits = bpe_logits;\n    this.wp_logits = wp_logits;\n  }\n\n  get logits() {\n    return [this.char_logits, this.bpe_logits, this.wp_logits];\n  }\n}\n\nexport class MgpstrPreTrainedModel extends PreTrainedModel { }\n\n/**\n * MGP-STR Model transformer with three classification heads on top\n * (three A^3 modules and three linear layer on top of the transformer encoder output) for scene text recognition (STR).\n */\nexport class MgpstrForSceneTextRecognition extends MgpstrPreTrainedModel {\n  /**\n   * @param {any} model_inputs\n   */\n  async _call(model_inputs: any) {\n    return new MgpstrModelOutput(await super._call(model_inputs) as { char_logits: Tensor, bpe_logits: Tensor, wp_logits: Tensor });\n  }\n}\n\n//////////////////////////////////////////////////\n// PatchTST Transformer models\nexport class PatchTSTPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare PatchTST Model outputting raw hidden-states without any specific head.\n */\nexport class PatchTSTModel extends PatchTSTPreTrainedModel { }\n\n/**\n * The PatchTST for prediction model.\n */\nexport class PatchTSTForPrediction extends PatchTSTPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// StyleTextToSpeech2 Transformer models\nexport class StyleTextToSpeech2PreTrainedModel extends PreTrainedModel { }\nexport class StyleTextToSpeech2Model extends StyleTextToSpeech2PreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// PatchTSMixer Transformer models\nexport class PatchTSMixerPreTrainedModel extends PreTrainedModel { }\n\n/**\n * The bare PatchTSMixer Model outputting raw hidden-states without any specific head.\n */\nexport class PatchTSMixerModel extends PatchTSMixerPreTrainedModel { }\n\n/**\n * The PatchTSMixer for prediction model.\n */\nexport class PatchTSMixerForPrediction extends PatchTSMixerPreTrainedModel { }\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\n// AutoModels, used to simplify construction of PreTrainedModels\n// (uses config to instantiate correct class)\n\n/**\n * Base class of all AutoModels. Contains the `from_pretrained` function\n * which is used to instantiate pretrained models.\n */\ninterface ModelOptions {\n  config?: PretrainedConfig | null;\n  cache_dir?: string | null;\n  local_files_only?: boolean;\n  revision?: string;\n  model_file_name?: string | null;\n  subfolder?: string;\n  device?: string | null;\n  dtype?: string | null;\n  use_external_data_format?: boolean | null;\n  session_options?: any;\n  progress_callback?: ProgressCallback | null;\n}\nexport class PretrainedMixin {\n  /**\n   * Mapping from model type to model class.\n   * @type {Map<string, any>[] | null}\n   */\n  static MODEL_CLASS_MAPPINGS: Map<string, any>[] | null = null;\n\n  /**\n   * Whether to attempt to instantiate the base class (`PretrainedModel`) if\n   * the model type is not found in the mapping.\n   */\n  static BASE_IF_FAIL = false;\n\n  /** @type {typeof PreTrainedModel.from_pretrained} */\n  static async from_pretrained(\n    pretrained_model_name_or_path: string,\n    {\n      progress_callback = null,\n      config = null,\n      cache_dir = null,\n      local_files_only = false,\n      revision = 'main',\n      model_file_name = null,\n      subfolder = 'onnx',\n      device = null,\n      dtype = null,\n      use_external_data_format = null,\n      session_options = {},\n    } = {},\n  ) {\n    const options: ModelOptions = {\n      progress_callback,\n      config,\n      cache_dir,\n      local_files_only,\n      revision,\n      model_file_name,\n      subfolder,\n      device,\n      dtype,\n      use_external_data_format,\n      session_options,\n    };\n    options.config = await AutoConfig.from_pretrained(pretrained_model_name_or_path, options);\n\n    if (!this.MODEL_CLASS_MAPPINGS) {\n      throw new Error('`MODEL_CLASS_MAPPINGS` not implemented for this type of `AutoClass`: ' + this.name);\n    }\n\n    for (const MODEL_CLASS_MAPPING of this.MODEL_CLASS_MAPPINGS) {\n      const modelInfo = MODEL_CLASS_MAPPING.get((options.config as any)?.model_type);\n      if (!modelInfo) {\n        continue; // Item not found in this mapping\n      }\n      return await modelInfo[1].from_pretrained(pretrained_model_name_or_path, options);\n    }\n\n    if (this.BASE_IF_FAIL) {\n      console.warn(`Unknown model class \"${(options.config as any)?.model_type}\", attempting to construct from base class.`);\n      return await PreTrainedModel.from_pretrained(pretrained_model_name_or_path, options);\n    } else {\n      throw Error(`Unsupported model type: ${(options.config as any)?.model_type}`);\n    }\n  }\n}\n\nconst MODEL_MAPPING_NAMES_ENCODER_ONLY = new Map([\n  ['clap', ['ClapModel', ClapModel]],\n  ['clip', ['CLIPModel', CLIPModel]],\n  ['chinese_clip', ['ChineseCLIPModel', ChineseCLIPModel]],\n  ['siglip', ['SiglipModel', SiglipModel]],\n  ['jina_clip', ['JinaCLIPModel', JinaCLIPModel]],\n  ['wav2vec2', ['Wav2Vec2Model', Wav2Vec2Model]],\n  ['wav2vec2-bert', ['Wav2Vec2BertModel', Wav2Vec2BertModel]],\n  ['unispeech', ['UniSpeechModel', UniSpeechModel]],\n  ['unispeech-sat', ['UniSpeechSatModel', UniSpeechSatModel]],\n  ['hubert', ['HubertModel', HubertModel]],\n  ['wavlm', ['WavLMModel', WavLMModel]],\n  ['audio-spectrogram-transformer', ['ASTModel', ASTModel]],\n  ['vits', ['VitsModel', VitsModel]],\n  ['pyannote', ['PyAnnoteModel', PyAnnoteModel]],\n  ['wespeaker-resnet', ['WeSpeakerResNetModel', WeSpeakerResNetModel]],\n\n  ['vit_mae', ['ViTMAEModel', ViTMAEModel]],\n  ['groupvit', ['GroupViTModel', GroupViTModel]],\n  ['swin2sr', ['Swin2SRModel', Swin2SRModel]],\n\n  ['hifigan', ['SpeechT5HifiGan', SpeechT5HifiGan]],\n\n  ['decision_transformer', ['DecisionTransformerModel', DecisionTransformerModel]],\n  ['patchtst', ['PatchTSTForPrediction', PatchTSTModel]],\n  ['patchtsmixer', ['PatchTSMixerForPrediction', PatchTSMixerModel]],\n\n  ['mgp-str', ['MgpstrForSceneTextRecognition', MgpstrForSceneTextRecognition]],\n  ['style_text_to_speech_2', ['StyleTextToSpeech2Model', StyleTextToSpeech2Model]],\n]);\n\nconst MODEL_MAPPING_NAMES_DECODER_ONLY = new Map([\n  ['bloom', ['BloomModel', BloomModel]],\n  ['jais', ['JAISModel', JAISModel]],\n  ['gpt2', ['GPT2Model', GPT2Model]],\n  ['gptj', ['GPTJModel', GPTJModel]],\n  ['gpt_bigcode', ['GPTBigCodeModel', GPTBigCodeModel]],\n  ['gpt_neo', ['GPTNeoModel', GPTNeoModel]],\n  ['gpt_neox', ['GPTNeoXModel', GPTNeoXModel]],\n  ['codegen', ['CodeGenModel', CodeGenModel]],\n  ['llama', ['LlamaModel', LlamaModel]],\n  ['exaone', ['ExaoneModel', ExaoneModel]],\n  ['olmo', ['OlmoModel', OlmoModel]],\n  ['olmo2', ['Olmo2Model', Olmo2Model]],\n  ['mobilellm', ['MobileLLMModel', MobileLLMModel]],\n  ['granite', ['GraniteModel', GraniteModel]],\n  ['cohere', ['CohereModel', CohereModel]],\n  ['gemma', ['GemmaModel', GemmaModel]],\n  ['gemma2', ['Gemma2Model', Gemma2Model]],\n  ['openelm', ['OpenELMModel', OpenELMModel]],\n  ['qwen2', ['Qwen2Model', Qwen2Model]],\n  ['phi', ['PhiModel', PhiModel]],\n  ['phi3', ['Phi3Model', Phi3Model]],\n  ['mpt', ['MptModel', MptModel]],\n  ['opt', ['OPTModel', OPTModel]],\n  ['mistral', ['MistralModel', MistralModel]],\n  ['starcoder2', ['Starcoder2Model', Starcoder2Model]],\n  ['falcon', ['FalconModel', FalconModel]],\n  ['stablelm', ['StableLmModel', StableLmModel]],\n]);\n\nconst MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES = new Map([\n  ['speecht5', ['SpeechT5ForSpeechToText', SpeechT5ForSpeechToText]],\n  ['whisper', ['WhisperForConditionalGeneration', WhisperForConditionalGeneration]],\n  ['moonshine', ['MoonshineForConditionalGeneration', MoonshineForConditionalGeneration]],\n]);\n\nconst MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES = new Map([\n  ['speecht5', ['SpeechT5ForTextToSpeech', SpeechT5ForTextToSpeech]],\n]);\n\nconst MODEL_FOR_TEXT_TO_WAVEFORM_MAPPING_NAMES = new Map([\n  ['vits', ['VitsModel', VitsModel]],\n  ['musicgen', ['MusicgenForConditionalGeneration', MusicgenForConditionalGeneration]],\n]);\n\nconst MODEL_FOR_CAUSAL_LM_MAPPING_NAMES = new Map([\n  ['bloom', ['BloomForCausalLM', BloomForCausalLM]],\n  ['gpt2', ['GPT2LMHeadModel', GPT2LMHeadModel]],\n  ['jais', ['JAISLMHeadModel', JAISLMHeadModel]],\n  ['gptj', ['GPTJForCausalLM', GPTJForCausalLM]],\n  ['gpt_bigcode', ['GPTBigCodeForCausalLM', GPTBigCodeForCausalLM]],\n  ['gpt_neo', ['GPTNeoForCausalLM', GPTNeoForCausalLM]],\n  ['gpt_neox', ['GPTNeoXForCausalLM', GPTNeoXForCausalLM]],\n  ['codegen', ['CodeGenForCausalLM', CodeGenForCausalLM]],\n  ['llama', ['LlamaForCausalLM', LlamaForCausalLM]],\n  ['exaone', ['ExaoneForCausalLM', ExaoneForCausalLM]],\n  ['olmo', ['OlmoForCausalLM', OlmoForCausalLM]],\n  ['olmo2', ['Olmo2ForCausalLM', Olmo2ForCausalLM]],\n  ['mobilellm', ['MobileLLMForCausalLM', MobileLLMForCausalLM]],\n  ['granite', ['GraniteForCausalLM', GraniteForCausalLM]],\n  ['cohere', ['CohereForCausalLM', CohereForCausalLM]],\n  ['gemma', ['GemmaForCausalLM', GemmaForCausalLM]],\n  ['gemma2', ['Gemma2ForCausalLM', Gemma2ForCausalLM]],\n  ['openelm', ['OpenELMForCausalLM', OpenELMForCausalLM]],\n  ['qwen2', ['Qwen2ForCausalLM', Qwen2ForCausalLM]],\n  ['phi', ['PhiForCausalLM', PhiForCausalLM]],\n  ['phi3', ['Phi3ForCausalLM', Phi3ForCausalLM]],\n  ['mpt', ['MptForCausalLM', MptForCausalLM]],\n  ['opt', ['OPTForCausalLM', OPTForCausalLM]],\n  ['mistral', ['MistralForCausalLM', MistralForCausalLM]],\n  ['starcoder2', ['Starcoder2ForCausalLM', Starcoder2ForCausalLM]],\n  ['falcon', ['FalconForCausalLM', FalconForCausalLM]],\n  ['trocr', ['TrOCRForCausalLM', TrOCRForCausalLM]],\n  ['stablelm', ['StableLmForCausalLM', StableLmForCausalLM]],\n\n  // Also image-text-to-text\n  ['phi3_v', ['Phi3VForCausalLM', Phi3VForCausalLM]],\n]);\n\nconst MODEL_FOR_MULTIMODALITY_MAPPING_NAMES = new Map([\n  ['multi_modality', ['MultiModalityCausalLM', MultiModalityCausalLM]],\n]);\n\nconst MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES = new Map([\n  ['idefics3', ['Idefics3ForConditionalGeneration', Idefics3ForConditionalGeneration]],\n]);\n\nconst MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES = new Map([\n  ['llava', ['LlavaForConditionalGeneration', LlavaForConditionalGeneration]],\n  ['llava_onevision', ['LlavaOnevisionForConditionalGeneration', LlavaOnevisionForConditionalGeneration]],\n  ['moondream1', ['Moondream1ForConditionalGeneration', Moondream1ForConditionalGeneration]],\n  ['florence2', ['Florence2ForConditionalGeneration', Florence2ForConditionalGeneration]],\n  //   ['qwen2-vl', ['Qwen2VLForConditionalGeneration', Qwen2VLForConditionalGeneration]],\n  ['idefics3', ['Idefics3ForConditionalGeneration', Idefics3ForConditionalGeneration]],\n  ['paligemma', ['PaliGemmaForConditionalGeneration', PaliGemmaForConditionalGeneration]],\n]);\n\nconst MODEL_FOR_MASK_GENERATION_MAPPING_NAMES = new Map([['sam', ['SamModel', SamModel]]]);\n\nconst MODEL_FOR_CTC_MAPPING_NAMES = new Map([\n  ['wav2vec2', ['Wav2Vec2ForCTC', Wav2Vec2ForCTC]],\n  ['wav2vec2-bert', ['Wav2Vec2BertForCTC', Wav2Vec2BertForCTC]],\n  ['unispeech', ['UniSpeechForCTC', UniSpeechForCTC]],\n  ['unispeech-sat', ['UniSpeechSatForCTC', UniSpeechSatForCTC]],\n  ['wavlm', ['WavLMForCTC', WavLMForCTC]],\n  ['hubert', ['HubertForCTC', HubertForCTC]],\n]);\n\nconst MODEL_FOR_AUDIO_XVECTOR_MAPPING_NAMES = new Map([['wavlm', ['WavLMForXVector', WavLMForXVector]]]);\n\nconst MODEL_FOR_IMAGE_MATTING_MAPPING_NAMES = new Map([\n  ['vitmatte', ['VitMatteForImageMatting', VitMatteForImageMatting]],\n]);\n\nconst MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES = new Map([\n  ['patchtst', ['PatchTSTForPrediction', PatchTSTModel]],\n  ['patchtsmixer', ['PatchTSMixerForPrediction', PatchTSMixerModel]],\n]);\n\nconst MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES = new Map([\n  ['swin2sr', ['Swin2SRForImageSuperResolution', Swin2SRForImageSuperResolution]],\n]);\n\nconst MODEL_FOR_POSE_ESTIMATION_MAPPING_NAMES = new Map([\n  ['vitpose', ['VitPoseForPoseEstimation', VitPoseForPoseEstimation]],\n]);\n\n// NOTE: This is custom to Transformers.js, and is necessary because certain models\n// (e.g., CLIP) are split into vision and text components\nconst MODEL_FOR_IMAGE_FEATURE_EXTRACTION_MAPPING_NAMES = new Map([\n  ['clip', ['CLIPVisionModelWithProjection', CLIPVisionModelWithProjection]],\n  ['siglip', ['SiglipVisionModel', SiglipVisionModel]],\n  ['jina_clip', ['JinaCLIPVisionModel', JinaCLIPVisionModel]],\n]);\n\nconst MODEL_CLASS_TYPE_MAPPING = [\n  [MODEL_MAPPING_NAMES_ENCODER_ONLY, MODEL_TYPES.EncoderOnly],\n  [MODEL_MAPPING_NAMES_DECODER_ONLY, MODEL_TYPES.DecoderOnly],\n  [MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES, MODEL_TYPES.Seq2Seq],\n  [MODEL_FOR_CAUSAL_LM_MAPPING_NAMES, MODEL_TYPES.DecoderOnly],\n  [MODEL_FOR_MULTIMODALITY_MAPPING_NAMES, MODEL_TYPES.MultiModality],\n  [MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES, MODEL_TYPES.Vision2Seq],\n  [MODEL_FOR_IMAGE_TEXT_TO_TEXT_MAPPING_NAMES, MODEL_TYPES.ImageTextToText],\n  [MODEL_FOR_IMAGE_MATTING_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_TIME_SERIES_PREDICTION_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_POSE_ESTIMATION_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_MASK_GENERATION_MAPPING_NAMES, MODEL_TYPES.MaskGeneration],\n  [MODEL_FOR_CTC_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES, MODEL_TYPES.Seq2Seq],\n  [MODEL_FOR_TEXT_TO_WAVEFORM_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n  [MODEL_FOR_AUDIO_XVECTOR_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n\n  // Custom:\n  [MODEL_FOR_IMAGE_FEATURE_EXTRACTION_MAPPING_NAMES, MODEL_TYPES.EncoderOnly],\n];\n\nfor (const [mappings, type] of MODEL_CLASS_TYPE_MAPPING) {\n  // @ts-ignore\n  for (const [name, model] of mappings.values()) {\n    MODEL_TYPE_MAPPING.set(name, type);\n    MODEL_CLASS_TO_NAME_MAPPING.set(model, name);\n    MODEL_NAME_TO_CLASS_MAPPING.set(name, model);\n  }\n}\n\nconst CUSTOM_MAPPING = [\n  // OVERRIDE:\n  // TODO: Refactor to allow class to specify model\n  ['MusicgenForConditionalGeneration', MusicgenForConditionalGeneration, MODEL_TYPES.Musicgen],\n  ['Phi3VForCausalLM', Phi3VForCausalLM, MODEL_TYPES.Phi3V],\n\n  ['CLIPTextModelWithProjection', CLIPTextModelWithProjection, MODEL_TYPES.EncoderOnly],\n  ['SiglipTextModel', SiglipTextModel, MODEL_TYPES.EncoderOnly],\n  ['JinaCLIPTextModel', JinaCLIPTextModel, MODEL_TYPES.EncoderOnly],\n  ['ClapTextModelWithProjection', ClapTextModelWithProjection, MODEL_TYPES.EncoderOnly],\n  ['ClapAudioModelWithProjection', ClapAudioModelWithProjection, MODEL_TYPES.EncoderOnly],\n];\nfor (const [name, model, type] of CUSTOM_MAPPING) {\n  MODEL_TYPE_MAPPING.set(name, type);\n  MODEL_CLASS_TO_NAME_MAPPING.set(model, name);\n  MODEL_NAME_TO_CLASS_MAPPING.set(name, model);\n}\n\n/**\n * Helper class which is used to instantiate pretrained models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModel.from_pretrained('Xenova/bert-base-uncased');\n */\nexport class AutoModel extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = MODEL_CLASS_TYPE_MAPPING.map((x) => x[0]) as Map<string, any>[];\n  static BASE_IF_FAIL = true;\n}\n\n/**\n * Helper class which is used to instantiate pretrained sequence-to-sequence speech-to-text models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForSpeechSeq2Seq.from_pretrained('openai/whisper-tiny.en');\n */\nexport class AutoModelForSpeechSeq2Seq extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING_NAMES];\n}\n\n/**\n * Helper class which is used to instantiate pretrained sequence-to-sequence text-to-spectrogram models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForTextToSpectrogram.from_pretrained('microsoft/speecht5_tts');\n */\nexport class AutoModelForTextToSpectrogram extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_TEXT_TO_SPECTROGRAM_MAPPING_NAMES];\n}\n\n/**\n * Helper class which is used to instantiate pretrained text-to-waveform models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForTextToSpectrogram.from_pretrained('facebook/mms-tts-eng');\n */\nexport class AutoModelForTextToWaveform extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_TEXT_TO_WAVEFORM_MAPPING_NAMES];\n}\n\n/**\n * Helper class which is used to instantiate pretrained causal language models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForCausalLM.from_pretrained('Xenova/gpt2');\n */\nexport class AutoModelForCausalLM extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_CAUSAL_LM_MAPPING_NAMES];\n}\n\n/**\n * Helper class which is used to instantiate pretrained vision-to-sequence models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForVision2Seq.from_pretrained('Xenova/vit-gpt2-image-captioning');\n */\nexport class AutoModelForVision2Seq extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_VISION_2_SEQ_MAPPING_NAMES];\n}\n\n/**\n * Helper class which is used to instantiate pretrained mask generation models with the `from_pretrained` function.\n * The chosen model class is determined by the type specified in the model config.\n *\n * @example\n * let model = await AutoModelForMaskGeneration.from_pretrained('Xenova/sam-vit-base');\n */\nexport class AutoModelForMaskGeneration extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_MASK_GENERATION_MAPPING_NAMES];\n}\n\nexport class AutoModelForCTC extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_CTC_MAPPING_NAMES];\n}\n\nexport class AutoModelForXVector extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_AUDIO_XVECTOR_MAPPING_NAMES];\n}\n\nexport class AutoModelForImageMatting extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_IMAGE_MATTING_MAPPING_NAMES];\n}\n\nexport class AutoModelForImageToImage extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_IMAGE_TO_IMAGE_MAPPING_NAMES];\n}\n\nexport class AutoModelForPoseEstimation extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_POSE_ESTIMATION_MAPPING_NAMES];\n}\n\nexport class AutoModelForImageFeatureExtraction extends PretrainedMixin {\n  static MODEL_CLASS_MAPPINGS = [MODEL_FOR_IMAGE_FEATURE_EXTRACTION_MAPPING_NAMES];\n}\n\n//////////////////////////////////////////////////\n\n//////////////////////////////////////////////////\nexport class Seq2SeqLMOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits The output logits of the model.\n   * @param {Tensor} output.past_key_values An tensor of key/value pairs that represent the previous state of the model.\n   * @param {Tensor} output.encoder_outputs The output of the encoder in a sequence-to-sequence model.\n   * @param {Tensor} [output.decoder_attentions] Attentions weights of the decoder, after the attention softmax, used to compute the weighted average in the self-attention heads.\n   * @param {Tensor} [output.cross_attentions] Attentions weights of the decoder's cross-attention layer, after the attention softmax, used to compute the weighted average in the cross-attention heads.\n   */\n  logits: Tensor;\n  past_key_values: Tensor;\n  encoder_outputs: Tensor;\n  decoder_attentions: Tensor | null;\n  cross_attentions: Tensor | null;\n  constructor({\n    logits,\n    past_key_values,\n    encoder_outputs,\n    decoder_attentions = null,\n    cross_attentions = null,\n  }: {\n    logits: Tensor;\n    past_key_values: Tensor;\n    encoder_outputs: Tensor;\n    decoder_attentions: Tensor | null;\n    cross_attentions: Tensor | null;\n  }) {\n    super();\n    this.logits = logits;\n    this.past_key_values = past_key_values;\n    this.encoder_outputs = encoder_outputs;\n    this.decoder_attentions = decoder_attentions;\n    this.cross_attentions = cross_attentions;\n  }\n}\n\n/**\n * Base class for outputs of sentence classification models.\n */\nexport class SequenceClassifierOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits classification (or regression if config.num_labels==1) scores (before SoftMax).\n   * @param {Record<string, Tensor>} [output.attentions] Object of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length, sequence_length)`.\n   * Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.\n   */\n  logits: Tensor;\n  attentions: Record<string, Tensor>;\n  constructor({ logits, ...attentions }: { logits: Tensor;[key: string]: Tensor }) {\n    super();\n    this.logits = logits;\n    this.attentions = attentions;\n  }\n}\n\n/**\n * Base class for outputs of XVector models.\n */\nexport class XVectorOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits Classification hidden states before AMSoftmax, of shape `(batch_size, config.xvector_output_dim)`.\n   * @param {Tensor} output.embeddings Utterance embeddings used for vector similarity-based retrieval, of shape `(batch_size, config.xvector_output_dim)`.\n   */\n  logits: Tensor;\n  embeddings: Tensor;\n  constructor({ logits, embeddings }: { logits: Tensor; embeddings: Tensor }) {\n    super();\n    this.logits = logits;\n    this.embeddings = embeddings;\n  }\n}\n\n/**\n * Base class for outputs of token classification models.\n */\nexport class TokenClassifierOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits Classification scores (before SoftMax).\n   */\n  logits: Tensor;\n  constructor({ logits }: { logits: Tensor }) {\n    super();\n    this.logits = logits;\n  }\n}\n\n/**\n * Base class for masked language models outputs.\n */\nexport class MaskedLMOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).\n   */\n  logits: Tensor;\n  constructor({ logits }: { logits: Tensor }) {\n    super();\n    this.logits = logits;\n  }\n}\n\n/**\n * Base class for outputs of question answering models.\n */\nexport class QuestionAnsweringModelOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.start_logits Span-start scores (before SoftMax).\n   * @param {Tensor} output.end_logits Span-end scores (before SoftMax).\n   */\n  start_logits: Tensor;\n  end_logits: Tensor;\n  constructor({ start_logits, end_logits }: { start_logits: Tensor; end_logits: Tensor }) {\n    super();\n    this.start_logits = start_logits;\n    this.end_logits = end_logits;\n  }\n}\n\n/**\n * Base class for causal language model (or autoregressive) outputs.\n */\nexport class CausalLMOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits Prediction scores of the language modeling head (scores for each vocabulary token before softmax).\n   */\n  logits: Tensor;\n  constructor({ logits }: { logits: Tensor }) {\n    super();\n    this.logits = logits;\n  }\n}\n\n/**\n * Base class for causal language model (or autoregressive) outputs.\n */\nexport class CausalLMOutputWithPast extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.logits Prediction scores of the language modeling head (scores for each vocabulary token before softmax).\n   * @param {Tensor} output.past_key_values Contains pre-computed hidden-states (key and values in the self-attention blocks)\n   * that can be used (see `past_key_values` input) to speed up sequential decoding.\n   */\n  logits: Tensor;\n  past_key_values: Tensor;\n  constructor({ logits, past_key_values }: { logits: Tensor; past_key_values: Tensor }) {\n    super();\n    this.logits = logits;\n    this.past_key_values = past_key_values;\n  }\n}\n\nexport class ImageMattingOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.alphas Estimated alpha values, of shape `(batch_size, num_channels, height, width)`.\n   */\n  alphas: Tensor;\n  constructor({ alphas }: { alphas: Tensor }) {\n    super();\n    this.alphas = alphas;\n  }\n}\n\n/**\n * Describes the outputs for the VITS model.\n */\nexport class VitsModelOutput extends ModelOutput {\n  /**\n   * @param {Object} output The output of the model.\n   * @param {Tensor} output.waveform The final audio waveform predicted by the model, of shape `(batch_size, sequence_length)`.\n   * @param {Tensor} output.spectrogram The log-mel spectrogram predicted at the output of the flow model.\n   * This spectrogram is passed to the Hi-Fi GAN decoder model to obtain the final audio waveform.\n   */\n  waveform: Tensor;\n  spectrogram: Tensor;\n  constructor({ waveform, spectrogram }: { waveform: Tensor; spectrogram: Tensor }) {\n    super();\n    this.waveform = waveform;\n    this.spectrogram = spectrogram;\n  }\n}\n","/**\n * @file Processors are used to prepare inputs (e.g., text, image or audio) for a model.\n *\n * **Example:** Using a `WhisperProcessor` to prepare an audio input for a model.\n * ```javascript\n * import { AutoProcessor, read_audio } from '@huggingface/transformers';\n *\n * const processor = await AutoProcessor.from_pretrained('openai/whisper-tiny.en');\n * const audio = await read_audio('https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac', 16000);\n * const { input_features } = await processor(audio);\n * // Tensor {\n * //   data: Float32Array(240000) [0.4752984642982483, 0.5597258806228638, 0.56434166431427, ...],\n * //   dims: [1, 80, 3000],\n * //   type: 'float32',\n * //   size: 240000,\n * // }\n * ```\n *\n * @module processors\n */\nimport { PROCESSOR_NAME } from '../utils/constants';\nimport { Callable } from '../utils/generic';\nimport { getModelJSON } from '../utils/hub';\n\n/**\n * @typedef {Object} ProcessorProperties Additional processor-specific properties.\n * @typedef {import('../utils/hub.js').PretrainedOptions & ProcessorProperties} PretrainedProcessorOptions\n * @typedef {import('../tokenizers.js').PreTrainedTokenizer} PreTrainedTokenizer\n */\n\n/**\n * Represents a Processor that extracts features from an input.\n */\nexport class Processor extends Callable {\n  static classes = ['image_processor_class', 'tokenizer_class', 'feature_extractor_class'] as const;\n  static uses_processor_config = false;\n\n  static image_processor_class: any;\n  static tokenizer_class: any;\n  static feature_extractor_class: any;\n\n  /**\n   * Creates a new Processor with the given components\n   * @param {Object} config\n   * @param {Record<string, Object>} components\n   */\n  config: Record<string, any>;\n  components: Record<string, any>;\n  constructor(config: Record<string, any>, components: Record<string, any>) {\n    super();\n    this.config = config;\n    this.components = components;\n  }\n\n  /**\n   * @returns {import('./image_processors_utils.js').ImageProcessor|undefined} The image processor of the processor, if it exists.\n   */\n  get image_processor() {\n    return this.components.image_processor;\n  }\n\n  /**\n   * @returns {PreTrainedTokenizer|undefined} The tokenizer of the processor, if it exists.\n   */\n  get tokenizer() {\n    return this.components.tokenizer;\n  }\n\n  /**\n   * @returns {import('./feature_extraction_utils.js').FeatureExtractor|undefined} The feature extractor of the processor, if it exists.\n   */\n  get feature_extractor() {\n    return this.components.feature_extractor;\n  }\n\n  /**\n   * @param {Parameters<PreTrainedTokenizer['apply_chat_template']>[0]} messages\n   * @param {Parameters<PreTrainedTokenizer['apply_chat_template']>[1]} options\n   * @returns {ReturnType<PreTrainedTokenizer['apply_chat_template']>}\n   */\n  apply_chat_template(messages: any, options: any = {}) {\n    if (!this.tokenizer) {\n      throw new Error('Unable to apply chat template without a tokenizer.');\n    }\n    return this.tokenizer.apply_chat_template(messages, {\n      tokenize: false, // default to false\n      ...options,\n    });\n  }\n\n  /**\n   * @param {Parameters<PreTrainedTokenizer['batch_decode']>} args\n   * @returns {ReturnType<PreTrainedTokenizer['batch_decode']>}\n   */\n  batch_decode(...args: any[]) {\n    if (!this.tokenizer) {\n      throw new Error('Unable to decode without a tokenizer.');\n    }\n    return this.tokenizer.batch_decode(...args);\n  }\n\n  /**\n   * @param {Parameters<PreTrainedTokenizer['decode']>} args\n   * @returns {ReturnType<PreTrainedTokenizer['decode']>}\n   */\n  decode(...args: any[]) {\n    if (!this.tokenizer) {\n      throw new Error('Unable to decode without a tokenizer.');\n    }\n    return this.tokenizer.decode(...args);\n  }\n\n  /**\n   * Calls the feature_extractor function with the given input.\n   * @param {any} input The input to extract features from.\n   * @param {...any} args Additional arguments.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(input: any, ...args: any[]) {\n    for (const item of [this.image_processor, this.feature_extractor, this.tokenizer]) {\n      if (item) {\n        return item(input, ...args);\n      }\n    }\n    throw new Error('No image processor, feature extractor, or tokenizer found.');\n  }\n\n  /**\n   * Instantiate one of the processor classes of the library from a pretrained model.\n   *\n   * The processor class to instantiate is selected based on the `image_processor_type` (or `feature_extractor_type`; legacy)\n   * property of the config object (either passed as an argument or loaded from `pretrained_model_name_or_path` if possible)\n   *\n   * @param {string} pretrained_model_name_or_path The name or path of the pretrained model. Can be either:\n   * - A string, the *model id* of a pretrained processor hosted inside a model repo on huggingface.co.\n   *   Valid model ids can be located at the root-level, like `bert-base-uncased`, or namespaced under a\n   *   user or organization name, like `dbmdz/bert-base-german-cased`.\n   * - A path to a *directory* containing processor files, e.g., `./my_model_directory/`.\n   * @param {PretrainedProcessorOptions} options Additional options for loading the processor.\n   *\n   * @returns {Promise<Processor>} A new instance of the Processor class.\n   */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: any) {\n    const [config, components] = await Promise.all([\n      // TODO:\n      this.uses_processor_config ? getModelJSON(pretrained_model_name_or_path, PROCESSOR_NAME, true, options) : {},\n      Promise.all(\n        this.classes\n          .filter((cls) => cls in this)\n          .map(async (cls) => {\n            const component = await this[cls].from_pretrained(pretrained_model_name_or_path, options);\n            return [cls.replace(/_class$/, ''), component];\n          }),\n      ).then(Object.fromEntries),\n    ]);\n\n    return new this(config, components);\n  }\n}\n","export * from './florence2/processing_florence2';\nexport * from './idefics3/processing_idefics3';\nexport * from './mgp_str/processing_mgp_str';\nexport * from './moonshine/processing_moonshine';\nexport * from './janus/processing_janus';\nexport * from './jina_clip/processing_jina_clip';\nexport * from './phi3_v/processing_phi3_v';\nexport * from './paligemma/processing_paligemma';\nexport * from './pyannote/processing_pyannote';\nexport * from './qwen2_vl/processing_qwen2_vl';\nexport * from './sam/processing_sam';\nexport * from './speecht5/processing_speecht5';\nexport * from './wav2vec2/processing_wav2vec2';\nexport * from './whisper/processing_whisper';\n","import { Callable } from '../utils/generic';\nimport { Tensor, interpolate, stack } from '../utils/tensor';\nimport { bankers_round, max, min, softmax } from '../utils/maths';\nimport { RawImage } from '../utils/image';\nimport { calculateReflectOffset, ProgressCallback } from '../utils/core.js';\nimport { getModelJSON, PretrainedOptions } from '../utils/hub.js';\nimport { IMAGE_PROCESSOR_NAME } from '../utils/constants.js';\n\n/**\n * Named tuple to indicate the order we are using is (height x width),\n * even though the Graphics' industry standard is (width x height).\n * @typedef {[height: number, width: number]} HeightWidth\n */\n\n/**\n * @typedef {object} ImageProcessorResult\n * @property {Tensor} pixel_values The pixel values of the batched preprocessed images.\n * @property {HeightWidth[]} original_sizes Array of two-dimensional tuples like [[480, 640]].\n * @property {HeightWidth[]} reshaped_input_sizes Array of two-dimensional tuples like [[1000, 1330]].\n */\n\n/**\n * Helper function to constrain a value to be a multiple of a number.\n * @param {number} val The value to constrain.\n * @param {number} multiple The number to constrain to.\n * @param {number} [minVal=0] The minimum value to constrain to.\n * @param {number} [maxVal=null] The maximum value to constrain to.\n * @returns {number} The constrained value.\n * @private\n */\nfunction constraint_to_multiple_of(val: number, multiple: number, minVal = 0, maxVal = null) {\n  const a = val / multiple;\n  let x = bankers_round(a) * multiple;\n\n  if (maxVal !== null && x > maxVal) {\n    x = Math.floor(a) * multiple;\n  }\n\n  if (x < minVal) {\n    x = Math.ceil(a) * multiple;\n  }\n\n  return x;\n}\n\n/**\n * Rounds the height and width down to the closest multiple of size_divisibility\n * @param {[number, number]} size The size of the image\n * @param {number} divisor The divisor to use.\n * @returns {[number, number]} The rounded size.\n */\nfunction enforce_size_divisibility(size: [number, number], divisor: number) {\n  return [Math.max(Math.floor(size[0] / divisor), 1) * divisor, Math.max(Math.floor(size[1] / divisor), 1) * divisor];\n}\n\n// Helper functions\n\n/**\n * Converts bounding boxes from center format to corners format.\n *\n * @param {number[]} arr The coordinate for the center of the box and its width, height dimensions (center_x, center_y, width, height)\n * @returns {number[]} The coodinates for the top-left and bottom-right corners of the box (top_left_x, top_left_y, bottom_right_x, bottom_right_y)\n */\nexport function center_to_corners_format(centerX: number, centerY: number, width: number, height: number) {\n  return [centerX - width / 2, centerY - height / 2, centerX + width / 2, centerY + height / 2];\n}\n\n/**\n * Post-processes the outputs of the model (for object detection).\n * @param {Object} outputs The outputs of the model that must be post-processed\n * @param {Tensor} outputs.logits The logits\n * @param {Tensor} outputs.pred_boxes The predicted boxes.\n * @param {number} [threshold=0.5] The threshold to use for the scores.\n * @param {[number, number][]} [target_sizes=null] The sizes of the original images.\n * @param {boolean} [is_zero_shot=false] Whether zero-shot object detection was performed.\n * @return {Object[]} An array of objects containing the post-processed outputs.\n */\nexport function post_process_object_detection(\n  outputs: any,\n  threshold = 0.5,\n  target_sizes: [number, number][] | null = null,\n  is_zero_shot = false,\n) {\n  const out_logits = outputs.logits;\n  const out_bbox = outputs.pred_boxes;\n  const [batch_size, num_boxes, num_classes] = out_logits.dims;\n\n  if (target_sizes !== null && target_sizes.length !== batch_size) {\n    throw Error('Make sure that you pass in as many target sizes as the batch dimension of the logits');\n  }\n  let toReturn = [];\n  for (let i = 0; i < batch_size; ++i) {\n    let target_size = target_sizes !== null ? target_sizes[i] : null;\n    let info: {\n      boxes: number[][];\n      classes: number[];\n      scores: number[];\n    } = {\n      boxes: [],\n      classes: [],\n      scores: [],\n    };\n    let logits = out_logits[i];\n    let bbox = out_bbox[i];\n\n    for (let j = 0; j < num_boxes; ++j) {\n      let logit = logits[j];\n\n      let indices = [];\n      let probs;\n      if (is_zero_shot) {\n        // Get indices of classes with high enough probability\n        probs = logit.sigmoid().data;\n        for (let k = 0; k < probs.length; ++k) {\n          if (probs[k] > threshold) {\n            indices.push(k);\n          }\n        }\n      } else {\n        // Get most probable class\n        let maxIndex = max(logit.data as Float32Array)[1];\n\n        if (maxIndex === num_classes - 1) {\n          // This is the background class, skip it\n          continue;\n        }\n        // Compute softmax over classes\n        probs = softmax(logit.data);\n\n        if (probs[Number(maxIndex)] < threshold) {\n          continue;\n        }\n        indices.push(maxIndex);\n      }\n\n      for (const index of indices) {\n        // Some class has a high enough probability\n        /** @type {number[]} */\n        let box = bbox[j].data;\n\n        // convert to [x0, y0, x1, y1] format\n        box = center_to_corners_format(box[0], box[1], box[2], box[3]);\n        if (target_size !== null) {\n          box = box.map((x: number, i: number) => x * target_size[(i + 1) % 2]);\n        }\n\n        info.boxes.push(box);\n        info.classes.push(Number(index));\n        info.scores.push(probs[Number(index)]);\n      }\n    }\n    toReturn.push(info);\n  }\n  return toReturn;\n}\n\n/**\n * Post-processes the outputs of the model (for semantic segmentation).\n * @param {*} outputs Raw outputs of the model.\n * @param {[number, number][]} [target_sizes=null] List of tuples corresponding to the requested final size\n * (height, width) of each prediction. If unset, predictions will not be resized.\n * @returns {{segmentation: Tensor; labels: number[]}[]} The semantic segmentation maps.\n */\nexport function post_process_semantic_segmentation(outputs: any, target_sizes: [number, number][] | null = null) {\n  const logits = outputs.logits;\n  const batch_size = logits.dims[0];\n\n  if (target_sizes !== null && target_sizes.length !== batch_size) {\n    throw Error('Make sure that you pass in as many target sizes as the batch dimension of the logits');\n  }\n\n  const toReturn = [];\n  for (let i = 0; i < batch_size; ++i) {\n    const target_size = target_sizes !== null ? target_sizes[i] : null;\n\n    let data = logits[i];\n\n    // 1. If target_size is not null, we need to resize the masks to the target size\n    if (target_size !== null) {\n      // resize the masks to the target size\n      data = interpolate(data, target_size, 'bilinear', false);\n    }\n    const [height, width] = target_size ?? data.dims.slice(-2);\n\n    const segmentation = new Tensor('int32', new Int32Array(height * width), [height, width]);\n\n    // Buffer to store current largest value\n    const buffer = data[0].data;\n    const segmentation_data = segmentation.data;\n    for (let j = 1; j < data.dims[0]; ++j) {\n      const row = data[j].data;\n      for (let k = 0; k < row.length; ++k) {\n        if (row[k] > buffer[k]) {\n          buffer[k] = row[k];\n          segmentation_data[k] = j;\n        }\n      }\n    }\n\n    // Store which objects have labels\n    // This is much more efficient that creating a set of the final values\n    const hasLabel = new Array(data.dims[0]);\n    for (let j = 0; j < segmentation_data.length; ++j) {\n      const index = segmentation_data[j];\n      hasLabel[index] = index;\n    }\n    /** @type {number[]} The unique list of labels that were detected */\n    const labels = hasLabel.filter((x) => x !== undefined);\n\n    toReturn.push({ segmentation, labels });\n  }\n  return toReturn;\n}\n\n/**\n * Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and `labels`.\n * @param {Tensor} class_logits The class logits.\n * @param {Tensor} mask_logits The mask logits.\n * @param {number} object_mask_threshold A number between 0 and 1 used to binarize the masks.\n * @param {number} num_labels The number of labels.\n * @returns {[Tensor[], number[], number[]]} The binarized masks, the scores, and the labels.\n * @private\n */\nfunction remove_low_and_no_objects(\n  class_logits: Tensor,\n  mask_logits: Tensor,\n  object_mask_threshold: number,\n  num_labels: number,\n) {\n  const mask_probs_item = [];\n  const pred_scores_item = [];\n  const pred_labels_item = [];\n\n  for (let j = 0; j < class_logits.dims[0]; ++j) {\n    const cls = class_logits[j];\n    const mask = mask_logits[j];\n\n    const pred_label = max(cls.data as Float32Array)[1];\n    if (pred_label === num_labels) {\n      // Is the background, so we ignore it\n      continue;\n    }\n\n    const scores = softmax(cls.data as Float32Array);\n    const pred_score = scores[Number(pred_label)];\n    if (pred_score > object_mask_threshold) {\n      mask_probs_item.push(mask);\n      pred_scores_item.push(pred_score);\n      pred_labels_item.push(pred_label);\n    }\n  }\n\n  return [mask_probs_item, pred_scores_item, pred_labels_item];\n}\n\n/**\n * Checks whether the segment is valid or not.\n * @param {Int32Array} mask_labels Labels for each pixel in the mask.\n * @param {Tensor[]} mask_probs Probabilities for each pixel in the masks.\n * @param {number} k The class id of the segment.\n * @param {number} mask_threshold The mask threshold.\n * @param {number} overlap_mask_area_threshold The overlap mask area threshold.\n * @returns {[boolean, number[]]} Whether the segment is valid or not, and the indices of the valid labels.\n * @private\n */\nfunction check_segment_validity(\n  mask_labels: Int32Array,\n  mask_probs: Tensor[],\n  k: number,\n  mask_threshold = 0.5,\n  overlap_mask_area_threshold = 0.8,\n) {\n  // mask_k is a 1D array of indices, indicating where the mask is equal to k\n  const mask_k = [];\n  let mask_k_area = 0;\n  let original_area = 0;\n\n  const mask_probs_k_data = mask_probs[k].data;\n\n  // Compute the area of all the stuff in query k\n  for (let i = 0; i < mask_labels.length; ++i) {\n    if (mask_labels[i] === k) {\n      mask_k.push(i);\n      ++mask_k_area;\n    }\n\n    if (mask_probs_k_data[i] >= mask_threshold) {\n      ++original_area;\n    }\n  }\n  let mask_exists = mask_k_area > 0 && original_area > 0;\n\n  // Eliminate disconnected tiny segments\n  if (mask_exists) {\n    // Perform additional check\n    let area_ratio = mask_k_area / original_area;\n    mask_exists = area_ratio > overlap_mask_area_threshold;\n  }\n\n  return [mask_exists, mask_k];\n}\n\n/**\n * Computes the segments.\n * @param {Tensor[]} mask_probs The mask probabilities.\n * @param {number[]} pred_scores The predicted scores.\n * @param {number[]} pred_labels The predicted labels.\n * @param {number} mask_threshold The mask threshold.\n * @param {number} overlap_mask_area_threshold The overlap mask area threshold.\n * @param {Set<number>} label_ids_to_fuse The label ids to fuse.\n * @param {number[]} target_size The target size of the image.\n * @returns {[Tensor, Array<{id: number, label_id: number, score: number}>]} The computed segments.\n * @private\n */\nfunction compute_segments(\n  mask_probs: Tensor[],\n  pred_scores: number[],\n  pred_labels: number[],\n  mask_threshold: number,\n  overlap_mask_area_threshold: number,\n  label_ids_to_fuse: Set<number>,\n  target_size: [number, number] | null = null,\n) {\n  const [height, width] = target_size ?? mask_probs[0].dims;\n\n  const segmentation = new Tensor('int32', new Int32Array(height * width), [height, width]);\n  const segments = [];\n\n  // 1. If target_size is not null, we need to resize the masks to the target size\n  if (target_size !== null) {\n    // resize the masks to the target size\n    for (let i = 0; i < mask_probs.length; ++i) {\n      mask_probs[i] = interpolate(mask_probs[i], target_size, 'bilinear', false);\n    }\n  }\n\n  // 2. Weigh each mask by its prediction score\n  // NOTE: `mask_probs` is updated in-place\n  //\n  // Temporary storage for the best label/scores for each pixel ([height, width]):\n  const mask_labels = new Int32Array(mask_probs[0].data.length);\n  const bestScores = new Float32Array(mask_probs[0].data.length);\n\n  for (let i = 0; i < mask_probs.length; ++i) {\n    let score = pred_scores[i];\n\n    const mask_probs_i_data = mask_probs[i].data;\n\n    for (let j = 0; j < mask_probs_i_data.length; ++j) {\n      mask_probs_i_data[j] *= score;\n      if (mask_probs_i_data[j] > bestScores[j]) {\n        mask_labels[j] = i;\n        bestScores[j] = mask_probs_i_data[j];\n      }\n    }\n  }\n\n  let current_segment_id = 0;\n\n  // let stuff_memory_list = {}\n  const segmentation_data = segmentation.data;\n  for (let k = 0; k < pred_labels.length; ++k) {\n    const pred_class = pred_labels[k];\n\n    // TODO add `should_fuse`\n    // let should_fuse = pred_class in label_ids_to_fuse\n\n    // Check if mask exists and large enough to be a segment\n    const [mask_exists, mask_k] = check_segment_validity(\n      mask_labels,\n      mask_probs,\n      k,\n      mask_threshold,\n      overlap_mask_area_threshold,\n    );\n\n    if (!mask_exists) {\n      // Nothing to see here\n      continue;\n    }\n\n    // TODO\n    // if (pred_class in stuff_memory_list) {\n    //     current_segment_id = stuff_memory_list[pred_class]\n    // } else {\n    //     current_segment_id += 1;\n    // }\n    ++current_segment_id;\n\n    // Add current object segment to final segmentation map\n    for (const index of mask_k as number[]) {\n      segmentation_data[index] = current_segment_id;\n    }\n\n    segments.push({\n      id: current_segment_id,\n      label_id: pred_class,\n      // was_fused: should_fuse, TODO\n      score: pred_scores[k],\n    });\n\n    // TODO\n    // if(should_fuse){\n    //     stuff_memory_list[pred_class] = current_segment_id\n    // }\n  }\n\n  return [segmentation, segments];\n}\n\n/**\n * Rescales the image so that the following conditions are met:\n *\n * 1. Both dimensions (height and width) are divisible by 'factor'.\n * 2. The total number of pixels is within the range ['min_pixels', 'max_pixels'].\n * 3. The aspect ratio of the image is maintained as closely as possible.\n *\n * @param {number} height The height of the image.\n * @param {number} width The width of the image.\n * @param {number} [factor=28] The factor to use for resizing.\n * @param {number} [min_pixels=56*56] The minimum number of pixels.\n * @param {number} [max_pixels=14*14*4*1280] The maximum number of pixels.\n * @returns {[number, number]} The new height and width of the image.\n * @throws {Error} If the height or width is smaller than the factor.\n */\nfunction smart_resize(\n  height: number,\n  width: number,\n  factor = 28,\n  min_pixels = 56 * 56,\n  max_pixels = 14 * 14 * 4 * 1280,\n) {\n  if (height < factor || width < factor) {\n    throw new Error(`height:${height} or width:${width} must be larger than factor:${factor}`);\n  } else if (Math.max(height, width) / Math.min(height, width) > 200) {\n    throw new Error(\n      `absolute aspect ratio must be smaller than 200, got ${Math.max(height, width) / Math.min(height, width)}`,\n    );\n  }\n\n  let h_bar = Math.round(height / factor) * factor;\n  let w_bar = Math.round(width / factor) * factor;\n\n  if (h_bar * w_bar > max_pixels) {\n    const beta = Math.sqrt((height * width) / max_pixels);\n    h_bar = Math.floor(height / beta / factor) * factor;\n    w_bar = Math.floor(width / beta / factor) * factor;\n  } else if (h_bar * w_bar < min_pixels) {\n    const beta = Math.sqrt(min_pixels / (height * width));\n    h_bar = Math.ceil((height * beta) / factor) * factor;\n    w_bar = Math.ceil((width * beta) / factor) * factor;\n  }\n\n  return [h_bar, w_bar];\n}\n\n/**\n * Post-process the model output to generate the final panoptic segmentation.\n * @param {*} outputs The model output to post process\n * @param {number} [threshold=0.5] The probability score threshold to keep predicted instance masks.\n * @param {number} [mask_threshold=0.5] Threshold to use when turning the predicted masks into binary values.\n * @param {number} [overlap_mask_area_threshold=0.8] The overlap mask area threshold to merge or discard small disconnected parts within each binary instance mask.\n * @param {Set<number>} [label_ids_to_fuse=null] The labels in this state will have all their instances be fused together.\n * @param {[number, number][]} [target_sizes=null] The target sizes to resize the masks to.\n * @returns {Array<{ segmentation: Tensor, segments_info: Array<{id: number, label_id: number, score: number}>}>}\n */\nexport function post_process_panoptic_segmentation(\n  outputs: any,\n  threshold = 0.5,\n  mask_threshold = 0.5,\n  overlap_mask_area_threshold = 0.8,\n  label_ids_to_fuse: Set<number> | null = null,\n  target_sizes: [number, number][] | null = null,\n) {\n  if (label_ids_to_fuse === null) {\n    console.warn('`label_ids_to_fuse` unset. No instance will be fused.');\n    label_ids_to_fuse = new Set();\n  }\n\n  const class_queries_logits = outputs.class_queries_logits ?? outputs.logits; // [batch_size, num_queries, num_classes+1]\n  const masks_queries_logits = outputs.masks_queries_logits ?? outputs.pred_masks; // [batch_size, num_queries, height, width]\n\n  const mask_probs = masks_queries_logits.sigmoid(); // [batch_size, num_queries, height, width]\n\n  let [batch_size, num_queries, num_labels] = class_queries_logits.dims;\n  num_labels -= 1; // Remove last class (background)\n\n  if (target_sizes !== null && target_sizes.length !== batch_size) {\n    throw Error('Make sure that you pass in as many target sizes as the batch dimension of the logits');\n  }\n\n  let toReturn = [];\n  for (let i = 0; i < batch_size; ++i) {\n    let target_size = target_sizes !== null ? target_sizes[i] : null;\n\n    let class_logits = class_queries_logits[i];\n    let mask_logits = mask_probs[i];\n\n    let [mask_probs_item, pred_scores_item, pred_labels_item] = remove_low_and_no_objects(\n      class_logits,\n      mask_logits,\n      threshold,\n      num_labels,\n    );\n\n    if (pred_labels_item.length === 0) {\n      // No mask found\n      let [height, width] = target_size ?? mask_logits.dims.slice(-2);\n\n      let segmentation = new Tensor('int32', new Int32Array(height * width).fill(-1), [height, width]);\n      toReturn.push({\n        segmentation: segmentation,\n        segments_info: [],\n      });\n      continue;\n    }\n\n    // Get segmentation map and segment information of batch item\n    let [segmentation, segments] = compute_segments(\n      mask_probs_item as Tensor[],\n      pred_scores_item as number[],\n      pred_labels_item as number[],\n      mask_threshold,\n      overlap_mask_area_threshold,\n      label_ids_to_fuse,\n      target_size,\n    );\n\n    toReturn.push({\n      segmentation: segmentation,\n      segments_info: segments,\n    });\n  }\n\n  return toReturn;\n}\n\n/**\n * Post-processes the outputs of the model (for instance segmentation).\n * @param {*} outputs Raw outputs of the model.\n * @param {number} [threshold=0.5] The probability score threshold to keep predicted instance masks.\n * @param {[number, number][]} [target_sizes=null] List of tuples corresponding to the requested final size\n * (height, width) of each prediction. If unset, predictions will not be resized.\n * @returns {Array<{ segmentation: Tensor, segments_info: Array<{id: number, label_id: number, score: number}>}>}\n */\nexport function post_process_instance_segmentation(\n  outputs: any,\n  threshold = 0.5,\n  target_sizes: [number, number][] | null = null,\n) {\n  throw new Error('`post_process_instance_segmentation` is not yet implemented.');\n}\n\n/**\n * @typedef {Object} ImageProcessorConfig A configuration object used to create an image processor.\n * @property {function} [progress_callback=null] If specified, this function will be called during model construction, to provide the user with progress updates.\n * @property {number[]} [image_mean] The mean values for image normalization.\n * @property {number[]} [image_std] The standard deviation values for image normalization.\n * @property {boolean} [do_rescale] Whether to rescale the image pixel values to the [0,1] range.\n * @property {number} [rescale_factor] The factor to use for rescaling the image pixel values.\n * @property {boolean} [do_normalize] Whether to normalize the image pixel values.\n * @property {boolean} [do_resize] Whether to resize the image.\n * @property {number} [resample] What method to use for resampling.\n * @property {number|Object} [size] The size to resize the image to.\n * @property {number|Object} [image_size] The size to resize the image to (same as `size`).\n * @property {boolean} [do_flip_channel_order=false] Whether to flip the color channels from RGB to BGR.\n * Can be overridden by the `do_flip_channel_order` parameter in the `preprocess` method.\n * @property {boolean} [do_center_crop] Whether to center crop the image to the specified `crop_size`.\n * Can be overridden by `do_center_crop` in the `preprocess` method.\n * @property {boolean} [do_thumbnail] Whether to resize the image using thumbnail method.\n * @property {boolean} [keep_aspect_ratio] If `true`, the image is resized to the largest possible size such that the aspect ratio is preserved.\n * Can be overidden by `keep_aspect_ratio` in `preprocess`.\n * @property {number} [ensure_multiple_of] If `do_resize` is `true`, the image is resized to a size that is a multiple of this value.\n * Can be overidden by `ensure_multiple_of` in `preprocess`.\n *\n * @property {number[]} [mean] The mean values for image normalization (same as `image_mean`).\n * @property {number[]} [std] The standard deviation values for image normalization (same as `image_std`).\n */\n\ninterface ImageProcessorConfig {\n  progress_callback?: ProgressCallback;\n  image_mean?: number[];\n  image_std?: number[];\n  do_rescale?: boolean;\n  rescale_factor?: number;\n  do_normalize?: boolean;\n  do_resize?: boolean;\n  resample?: number;\n  size?: number | { height: number; width: number };\n  image_size?: number | { height: number; width: number };\n  do_flip_channel_order?: boolean;\n  do_center_crop?: boolean;\n  do_thumbnail?: boolean;\n  keep_aspect_ratio?: boolean;\n  ensure_multiple_of?: number;\n  mean?: number[];\n  std?: number[];\n  crop_size?: number | { height: number; width: number };\n  do_crop_margin?: boolean;\n  do_convert_rgb?: boolean;\n}\n\nexport class ImageProcessor extends Callable {\n  protected image_mean?: number[];\n  protected image_std?: number[];\n  protected resample: number;\n  protected do_rescale: boolean;\n  protected rescale_factor: number;\n  protected do_normalize?: boolean;\n  protected do_thumbnail?: boolean;\n  protected size?: number | { height: number; width: number };\n  protected do_resize: boolean;\n  protected size_divisibility?: number;\n  protected do_center_crop?: boolean;\n  protected crop_size?: number | { height: number; width: number };\n  protected do_flip_channel_order: boolean;\n  protected config: ImageProcessorConfig;\n  protected pad_size?: { width: number; height: number };\n  protected do_pad?: boolean;\n  protected do_crop_margin?: boolean;\n  protected do_convert_rgb?: boolean;\n\n  /**\n   * Constructs a new `ImageProcessor`.\n   * @param {ImageProcessorConfig} config The configuration object.\n   */\n  constructor(config: ImageProcessorConfig) {\n    super();\n\n    this.image_mean = config.image_mean ?? config.mean;\n    this.image_std = config.image_std ?? config.std;\n\n    this.resample = config.resample ?? 2; // 2 => bilinear\n    this.do_rescale = config.do_rescale ?? true;\n    this.rescale_factor = config.rescale_factor ?? 1 / 255;\n    this.do_normalize = config.do_normalize;\n\n    this.do_thumbnail = config.do_thumbnail;\n    this.size = config.size ?? config.image_size;\n    this.do_resize = config.do_resize ?? this.size !== undefined;\n    // @ts-expect-error TS2339\n    this.size_divisibility = config.size_divisibility ?? config.size_divisor;\n\n    this.do_center_crop = config.do_center_crop;\n    this.crop_size = config.crop_size;\n    this.do_convert_rgb = config.do_convert_rgb ?? true;\n    this.do_crop_margin = config.do_crop_margin;\n\n    // @ts-expect-error TS2339\n    this.pad_size = config.pad_size;\n    // @ts-expect-error TS2339\n    this.do_pad = config.do_pad;\n\n    if (\n      this.do_pad &&\n      !this.pad_size &&\n      this.size &&\n      typeof this.size === 'object' &&\n      'width' in this.size &&\n      'height' in this.size\n    ) {\n      // Should pad, but no pad size specified\n      // We infer the pad size from the resize size\n      this.pad_size = this.size;\n    }\n\n    this.do_flip_channel_order = config.do_flip_channel_order ?? false;\n\n    this.config = config;\n  }\n\n  /**\n   * Resize the image to make a thumbnail. The image is resized so that no dimension is larger than any\n   * corresponding dimension of the specified size.\n   * @param {RawImage} image The image to be resized.\n   * @param {{height:number, width:number}} size The size `{\"height\": h, \"width\": w}` to resize the image to.\n   * @param {string | 0 | 1 | 2 | 3 | 4 | 5} [resample=2] The resampling filter to use.\n   * @returns {Promise<RawImage>} The resized image.\n   */\n  async thumbnail(image: RawImage, size: { height: number; width: number }, resample = 2) {\n    const input_height = image.height;\n    const input_width = image.width;\n\n    const output_height = size.height;\n    const output_width = size.width;\n\n    // We always resize to the smallest of either the input or output size.\n    let height = Math.min(input_height, output_height);\n    let width = Math.min(input_width, output_width);\n\n    if (height === input_height && width === input_width) {\n      return image;\n    }\n    if (input_height > input_width) {\n      width = Math.floor((input_width * height) / input_height);\n    } else if (input_width > input_height) {\n      height = Math.floor((input_height * width) / input_width);\n    }\n    return await image.resize(width, height, { resample });\n  }\n\n  /**\n   * Crops the margin of the image. Gray pixels are considered margin (i.e., pixels with a value below the threshold).\n   * @param {RawImage} image The image to be cropped.\n   * @param {number} gray_threshold Value below which pixels are considered to be gray.\n   * @returns {Promise<RawImage>} The cropped image.\n   */\n  async crop_margin(image: RawImage, gray_threshold = 200) {\n    const gray_image = image.clone().grayscale();\n\n    const minValue = min(gray_image.data)[0];\n    const maxValue = max(gray_image.data)[0];\n    const diff = BigInt(maxValue) - BigInt(minValue);\n\n    if (Number(diff) === 0) {\n      return image;\n    }\n\n    const threshold = gray_threshold / 255;\n\n    let x_min = gray_image.width,\n      y_min = gray_image.height,\n      x_max = 0,\n      y_max = 0;\n    const gray_image_data = gray_image.data;\n    for (let j = 0; j < gray_image.height; ++j) {\n      const row = j * gray_image.width;\n      for (let i = 0; i < gray_image.width; ++i) {\n        if ((Number(gray_image_data[row + i]) - Number(minValue)) / Number(diff) < threshold) {\n          // We have a non-zero pixel, so we update the min/max values accordingly\n          x_min = Math.min(x_min, i);\n          y_min = Math.min(y_min, j);\n          x_max = Math.max(x_max, i);\n          y_max = Math.max(y_max, j);\n        }\n      }\n    }\n\n    image = await image.crop([x_min, y_min, x_max, y_max]);\n    return image;\n  }\n\n  /**\n   * Pad the image by a certain amount.\n   * @param {Float32Array} pixelData The pixel data to pad.\n   * @param {number[]} imgDims The dimensions of the image (height, width, channels).\n   * @param {{width:number; height:number}|number|'square'} padSize The dimensions of the padded image.\n   * @param {Object} options The options for padding.\n   * @param {'constant'|'symmetric'} [options.mode='constant'] The type of padding to add.\n   * @param {boolean} [options.center=false] Whether to center the image.\n   * @param {number|number[]} [options.constant_values=0] The constant value to use for padding.\n   * @returns {[Float32Array, number[]]} The padded pixel data and image dimensions.\n   */\n  pad_image(\n    pixelData: Float32Array,\n    imgDims: number[],\n    padSize: number | { height: number; width: number } | 'square',\n    constant_values: number | number[] = 0,\n    mode: 'constant' | 'symmetric' = 'constant',\n    center: boolean = false,\n  ): [Float32Array, number[]] {\n    const [imageHeight, imageWidth, imageChannels] = imgDims;\n\n    let paddedImageWidth, paddedImageHeight;\n    if (typeof padSize === 'number') {\n      paddedImageWidth = padSize;\n      paddedImageHeight = padSize;\n    } else if (padSize === 'square') {\n      paddedImageWidth = paddedImageHeight = Math.max(imageHeight, imageWidth);\n    } else {\n      paddedImageWidth = padSize.width;\n      paddedImageHeight = padSize.height;\n    }\n\n    // Only add padding if there is a difference in size\n    if (paddedImageWidth !== imageWidth || paddedImageHeight !== imageHeight) {\n      const paddedPixelData = new Float32Array(paddedImageWidth * paddedImageHeight * imageChannels);\n      if (Array.isArray(constant_values)) {\n        // Fill with constant values, cycling through the array\n        for (let i = 0; i < paddedPixelData.length; ++i) {\n          paddedPixelData[i] = constant_values[i % imageChannels];\n        }\n      } else if (constant_values !== 0) {\n        paddedPixelData.fill(constant_values);\n      }\n\n      const [left, top] = center\n        ? [Math.floor((paddedImageWidth - imageWidth) / 2), Math.floor((paddedImageHeight - imageHeight) / 2)]\n        : [0, 0];\n\n      // Copy the original image into the padded image\n      for (let i = 0; i < imageHeight; ++i) {\n        const a = (i + top) * paddedImageWidth;\n        const b = i * imageWidth;\n        for (let j = 0; j < imageWidth; ++j) {\n          const c = (a + j + left) * imageChannels;\n          const d = (b + j) * imageChannels;\n          for (let k = 0; k < imageChannels; ++k) {\n            paddedPixelData[c + k] = pixelData[d + k];\n          }\n        }\n      }\n\n      if (mode === 'symmetric') {\n        if (center) {\n          throw new Error('`center` padding is not supported when `mode` is set to `symmetric`.');\n          // TODO: Implement this\n        }\n        const h1 = imageHeight - 1;\n        const w1 = imageWidth - 1;\n        for (let i = 0; i < paddedImageHeight; ++i) {\n          const a = i * paddedImageWidth;\n          const b = calculateReflectOffset(i, h1) * imageWidth;\n\n          for (let j = 0; j < paddedImageWidth; ++j) {\n            if (i < imageHeight && j < imageWidth) continue; // Do not overwrite original image\n            const c = (a + j) * imageChannels;\n            const d = (b + calculateReflectOffset(j, w1)) * imageChannels;\n\n            // Copy channel-wise\n            for (let k = 0; k < imageChannels; ++k) {\n              paddedPixelData[c + k] = pixelData[d + k];\n            }\n          }\n        }\n      }\n\n      // Update pixel data and image dimensions\n      pixelData = paddedPixelData;\n      imgDims = [paddedImageHeight, paddedImageWidth, imageChannels];\n    }\n    return [pixelData, imgDims];\n  }\n\n  /**\n   * Rescale the image' pixel values by `this.rescale_factor`.\n   * @param {Float32Array} pixelData The pixel data to rescale.\n   * @returns {void}\n   */\n  rescale(pixelData: Float32Array) {\n    for (let i = 0; i < pixelData.length; ++i) {\n      pixelData[i] = this.rescale_factor * pixelData[i];\n    }\n  }\n\n  /**\n   * Find the target (width, height) dimension of the output image after\n   * resizing given the input image and the desired size.\n   * @param {RawImage} image The image to resize.\n   * @param {any} size The size to use for resizing the image.\n   * @returns {[number, number]} The target (width, height) dimension of the output image after resizing.\n   */\n  get_resize_output_image_size(image: RawImage, size: any) {\n    // `size` comes in many forms, so we need to handle them all here:\n    // 1. `size` is an integer, in which case we resize the image to be a square\n\n    const [srcWidth, srcHeight] = image.size;\n\n    let shortest_edge;\n    let longest_edge;\n\n    if (this.do_thumbnail) {\n      // NOTE: custom logic for `Donut` models\n      const { height, width } = size;\n      shortest_edge = Math.min(height, width);\n    }\n    // Support both formats for backwards compatibility\n    else if (Number.isInteger(size)) {\n      shortest_edge = size;\n      // @ts-expect-error TS2339\n      longest_edge = this.config.max_size ?? shortest_edge;\n    } else if (size !== undefined) {\n      // Extract known properties from `size`\n      shortest_edge = size.shortest_edge;\n      longest_edge = size.longest_edge;\n    }\n\n    // If `longest_edge` and `shortest_edge` are set, maintain aspect ratio and resize to `shortest_edge`\n    // while keeping the largest dimension <= `longest_edge`\n    if (shortest_edge !== undefined || longest_edge !== undefined) {\n      // http://opensourcehacker.com/2011/12/01/calculate-aspect-ratio-conserving-resize-for-images-in-javascript/\n      // Try resize so that shortest edge is `shortest_edge` (target)\n      const shortResizeFactor =\n        shortest_edge === undefined\n          ? 1 // If `shortest_edge` is not set, don't upscale\n          : Math.max(shortest_edge / srcWidth, shortest_edge / srcHeight);\n\n      const newWidth = srcWidth * shortResizeFactor;\n      const newHeight = srcHeight * shortResizeFactor;\n\n      // The new width and height might be greater than `longest_edge`, so\n      // we downscale again to ensure the largest dimension is `longest_edge`\n      const longResizeFactor =\n        longest_edge === undefined\n          ? 1 // If `longest_edge` is not set, don't downscale\n          : Math.min(longest_edge / newWidth, longest_edge / newHeight);\n\n      // To avoid certain floating point precision issues, we round to 2 decimal places\n      let finalWidth = Math.floor(Number((newWidth * longResizeFactor).toFixed(2)));\n      let finalHeight = Math.floor(Number((newHeight * longResizeFactor).toFixed(2)));\n\n      if (this.size_divisibility !== undefined) {\n        [finalWidth, finalHeight] = enforce_size_divisibility([finalWidth, finalHeight], this.size_divisibility);\n      }\n      return [finalWidth, finalHeight];\n    } else if (size !== undefined && size.width !== undefined && size.height !== undefined) {\n      // If `width` and `height` are set, resize to those dimensions\n\n      let newWidth = size.width;\n      let newHeight = size.height;\n\n      // Custom for DPT models\n      if (this.config.keep_aspect_ratio && this.config.ensure_multiple_of) {\n        // determine new height and width\n        let scale_height = newHeight / srcHeight;\n        let scale_width = newWidth / srcWidth;\n\n        // scale as little as possible\n        if (Math.abs(1 - scale_width) < Math.abs(1 - scale_height)) {\n          // fit width\n          scale_height = scale_width;\n        } else {\n          // fit height\n          scale_width = scale_height;\n        }\n\n        newHeight = constraint_to_multiple_of(scale_height * srcHeight, this.config.ensure_multiple_of);\n        newWidth = constraint_to_multiple_of(scale_width * srcWidth, this.config.ensure_multiple_of);\n      }\n\n      return [newWidth, newHeight];\n    } else if (this.size_divisibility !== undefined) {\n      return enforce_size_divisibility([srcWidth, srcHeight], this.size_divisibility);\n    } else if (size.min_pixels !== undefined && size.max_pixels !== undefined) {\n      // Custom resize logic for Qwen2-VL models\n      const { min_pixels, max_pixels } = size;\n      // @ts-expect-error TS2339\n      const factor = this.config.patch_size * this.config.merge_size;\n      return smart_resize(srcHeight, srcWidth, factor, min_pixels, max_pixels);\n    } else {\n      throw new Error(\n        `Could not resize image due to unsupported \\`this.size\\` option in config: ${JSON.stringify(size)}`,\n      );\n    }\n  }\n\n  /**\n   * Resizes the image.\n   * @param {RawImage} image The image to resize.\n   * @returns {Promise<RawImage>} The resized image.\n   */\n  async resize(image: RawImage) {\n    const [newWidth, newHeight] = this.get_resize_output_image_size(image, this.size);\n    return await image.resize(newWidth, newHeight, {\n      resample: this.resample,\n    });\n  }\n\n  /**\n   * @typedef {object} PreprocessedImage\n   * @property {HeightWidth} original_size The original size of the image.\n   * @property {HeightWidth} reshaped_input_size The reshaped input size of the image.\n   * @property {Tensor} pixel_values The pixel values of the preprocessed image.\n   */\n\n  /**\n   * Preprocesses the given image.\n   *\n   * @param {RawImage} image The image to preprocess.\n   * @param {Object} overrides The overrides for the preprocessing options.\n   * @returns {Promise<PreprocessedImage>} The preprocessed image.\n   */\n  async preprocess(\n    image: RawImage,\n    {\n      do_normalize = null,\n      do_pad = null,\n      do_convert_rgb = null,\n      do_convert_grayscale = null,\n      do_flip_channel_order = null,\n    } = {},\n  ) {\n    if (this.do_crop_margin) {\n      // NOTE: Specific to nougat processors. This is done before resizing,\n      // and can be interpreted as a pre-preprocessing step.\n      image = await this.crop_margin(image);\n    }\n\n    const [srcWidth, srcHeight] = image.size; // original image size\n\n    // Convert image to RGB if specified in config.\n    if (do_convert_rgb ?? this.do_convert_rgb) {\n      image = image.rgb();\n    } else if (do_convert_grayscale) {\n      image = image.grayscale();\n    }\n\n    // TODO:\n    // For efficiency reasons, it might be best to merge the resize and center crop operations into one.\n\n    // Resize all images\n    if (this.do_resize) {\n      image = await this.resize(image);\n    }\n\n    // Resize the image using thumbnail method.\n    if (this.do_thumbnail) {\n      // @ts-expect-error TS2345\n      image = await this.thumbnail(image, this.size, this.resample);\n    }\n\n    if (this.do_center_crop) {\n      let crop_width;\n      let crop_height;\n      if (Number.isInteger(this.crop_size)) {\n        crop_width = this.crop_size;\n        crop_height = this.crop_size;\n      } else if (typeof this.crop_size === 'object' && this.crop_size !== null) {\n        crop_width = this.crop_size.width;\n        crop_height = this.crop_size.height;\n      }\n\n      image = await image.center_crop(crop_width as number, crop_height as number);\n    }\n\n    /** @type {HeightWidth} */\n    const reshaped_input_size = [image.height, image.width];\n\n    // NOTE: All pixel-level manipulation (i.e., modifying `pixelData`)\n    // occurs with data in the hwc format (height, width, channels),\n    // to emulate the behavior of the original Python code (w/ numpy).\n    /** @type {Float32Array} */\n    let pixelData = Float32Array.from(image.data);\n    let imgDims = [image.height, image.width, image.channels];\n\n    if (this.do_rescale) {\n      this.rescale(pixelData);\n    }\n\n    if (do_normalize ?? this.do_normalize) {\n      let image_mean = this.image_mean;\n      if (!Array.isArray(this.image_mean)) {\n        image_mean = new Array(image.channels).fill(image_mean);\n      }\n\n      let image_std = this.image_std;\n      if (!Array.isArray(this.image_std)) {\n        image_std = new Array(image.channels).fill(image_mean);\n      }\n\n      if (!image_mean || !image_std) {\n        throw new Error('image_mean and image_std must be defined when normalizing');\n      }\n\n      if (image_mean.length !== image.channels || image_std.length !== image.channels) {\n        throw new Error(\n          `When set to arrays, the length of \\`image_mean\\` (${image_mean.length}) and \\`image_std\\` (${image_std.length}) must match the number of channels in the image (${image.channels}).`,\n        );\n      }\n\n      for (let i = 0; i < pixelData.length; i += image.channels) {\n        for (let j = 0; j < image.channels; ++j) {\n          pixelData[i + j] = (pixelData[i + j] - image_mean[j]) / image_std[j];\n        }\n      }\n    }\n\n    // do padding after rescaling/normalizing\n    if (do_pad ?? this.do_pad) {\n      if (this.pad_size) {\n        const padded = this.pad_image(pixelData, [image.height, image.width, image.channels], this.pad_size);\n        [pixelData, imgDims] = padded as [Float32Array, number[]];\n      } else if (this.size_divisibility) {\n        const [paddedWidth, paddedHeight] = enforce_size_divisibility([imgDims[1], imgDims[0]], this.size_divisibility);\n        [pixelData, imgDims] = this.pad_image(pixelData, imgDims, { width: paddedWidth, height: paddedHeight });\n      }\n    }\n\n    if (do_flip_channel_order ?? this.do_flip_channel_order) {\n      if (imgDims[2] !== 3) {\n        throw new Error('Flipping channel order is only supported for RGB images.');\n      }\n      // Convert RGB to BGR\n      for (let i = 0; i < pixelData.length; i += 3) {\n        const temp = pixelData[i];\n        pixelData[i] = pixelData[i + 2];\n        pixelData[i + 2] = temp;\n      }\n    }\n\n    const pixel_values = new Tensor('float32', pixelData, imgDims).permute(2, 0, 1); // convert to channel dimension format (hwc -> chw)\n\n    return {\n      original_size: [srcHeight, srcWidth],\n      reshaped_input_size: reshaped_input_size,\n      pixel_values,\n    };\n  }\n\n  /**\n   * Calls the feature extraction process on an array of images,\n   * preprocesses each image, and concatenates the resulting\n   * features into a single Tensor.\n   * @param {RawImage[]} images The image(s) to extract features from.\n   * @param {...any} args Additional arguments.\n   * @returns {Promise<ImageProcessorResult>} An object containing the concatenated pixel values (and other metadata) of the preprocessed images.\n   */\n  async _call(images: RawImage[], ...args: any[]) {\n    if (!Array.isArray(images)) {\n      images = [images];\n    }\n    /** @type {PreprocessedImage[]} */\n    const imageData = await Promise.all(images.map((x) => this.preprocess(x)));\n\n    // Stack pixel values\n    const pixel_values = stack(\n      imageData.map((x) => x.pixel_values),\n      0,\n    );\n\n    return {\n      pixel_values,\n\n      // Original sizes of images\n      original_sizes: imageData.map((x) => x.original_size),\n\n      // Reshaped sizes of images, before padding or cropping\n      reshaped_input_sizes: imageData.map((x) => x.reshaped_input_size),\n    };\n  }\n\n  /**\n   * Instantiate one of the processor classes of the library from a pretrained model.\n   *\n   * The processor class to instantiate is selected based on the `image_processor_type` (or `feature_extractor_type`; legacy)\n   * property of the config object (either passed as an argument or loaded from `pretrained_model_name_or_path` if possible)\n   *\n   * @param {string} pretrained_model_name_or_path The name or path of the pretrained model. Can be either:\n   * - A string, the *model id* of a pretrained processor hosted inside a model repo on huggingface.co.\n   *   Valid model ids can be located at the root-level, like `bert-base-uncased`, or namespaced under a\n   *   user or organization name, like `dbmdz/bert-base-german-cased`.\n   * - A path to a *directory* containing processor files, e.g., `./my_model_directory/`.\n   * @param {import('../utils/hub.js').PretrainedOptions} options Additional options for loading the processor.\n   *\n   * @returns {Promise<ImageProcessor>} A new instance of the Processor class.\n   */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: PretrainedOptions) {\n    const preprocessorConfig = await getModelJSON(pretrained_model_name_or_path, IMAGE_PROCESSOR_NAME, true, options);\n    return new this(preprocessorConfig);\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class VLMImageProcessor extends ImageProcessor {\n  constructor(config) {\n    super({\n      do_pad: true,\n      pad_size: {\n        width: config.image_size,\n        height: config.image_size,\n      },\n      ...config,\n    });\n    // @ts-expect-error TS2339\n    this.constant_values = this.config.background_color.map((x) => x * this.rescale_factor);\n  }\n\n  pad_image(pixelData, imgDims, padSize, options) {\n    return super.pad_image(pixelData, imgDims, padSize, {\n      constant_values: this.constant_values,\n      center: true,\n      ...options,\n    });\n  }\n}\n","import { GITHUB_ISSUE_URL, IMAGE_PROCESSOR_NAME } from '../../utils/constants';\nimport { getModelJSON } from '../../utils/hub';\nimport { ImageProcessor } from '../../base/image_processors_utils';\nimport { VLMImageProcessor } from '../janus/image_processing_janus';\n\n// Map of processor types to their implementations\nconst PROCESSOR_MAPPING = {\n  'VLMImageProcessor': VLMImageProcessor,\n  'ImageProcessor': ImageProcessor,\n};\n\nexport class AutoImageProcessor {\n  /** @type {typeof ImageProcessor.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: Record<string, unknown> = {}) {\n    const preprocessorConfig = await getModelJSON(pretrained_model_name_or_path, IMAGE_PROCESSOR_NAME, true, options);\n\n    // Determine image processor class\n    const key = preprocessorConfig.image_processor_type ?? preprocessorConfig.feature_extractor_type;\n    let image_processor_class = ImageProcessor;\n\n    if (key && key in PROCESSOR_MAPPING) {\n      image_processor_class = PROCESSOR_MAPPING[key as keyof typeof PROCESSOR_MAPPING];\n    } else if (key !== undefined) {\n      console.warn(\n        `Image processor type '${key}' not found, assuming base ImageProcessor. Please report this at ${GITHUB_ISSUE_URL}.`\n      );\n    }\n\n    // Instantiate image processor\n    return new image_processor_class(preprocessorConfig);\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\n\nexport class Florence2Processor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static image_processor_class = AutoImageProcessor;\n\n  tasks_answer_post_processing_type: Map<string, string>;\n  task_prompts_without_inputs: Map<string, string>;\n  task_prompts_with_input: Map<string, string>;\n  regexes: Record<string, RegExp>;\n  size_per_bin: number;\n\n  constructor(config: any, components: any) {\n    super(config, components);\n\n    const { tasks_answer_post_processing_type, task_prompts_without_inputs, task_prompts_with_input } =\n      this.image_processor.config;\n\n    /** @type {Map<string, string>} */\n    this.tasks_answer_post_processing_type = new Map(Object.entries(tasks_answer_post_processing_type ?? {}));\n\n    /** @type {Map<string, string>} */\n    this.task_prompts_without_inputs = new Map(Object.entries(task_prompts_without_inputs ?? {}));\n\n    /** @type {Map<string, string>} */\n    this.task_prompts_with_input = new Map(Object.entries(task_prompts_with_input ?? {}));\n\n    this.regexes = {\n      quad_boxes: /(.+?)<loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)>/gm,\n      bboxes: /([^<]+)?<loc_(\\d+)><loc_(\\d+)><loc_(\\d+)><loc_(\\d+)>/gm,\n    };\n    this.size_per_bin = 1000;\n  }\n\n  /**\n   * Helper function to construct prompts from input texts\n   * @param {string|string[]} text\n   * @returns {string[]}\n   */\n  construct_prompts(text: string | string[]) {\n    if (typeof text === 'string') {\n      text = [text];\n    }\n\n    const prompts = [];\n    for (const t of text) {\n      // 1. fixed task prompts without additional inputs\n      if (this.task_prompts_without_inputs.has(t)) {\n        prompts.push(this.task_prompts_without_inputs.get(t));\n      }\n      // 2. task prompts with additional inputs\n      else {\n        for (const [task, prompt] of this.task_prompts_with_input) {\n          if (t.includes(task)) {\n            prompts.push(prompt.replaceAll('{input}', t).replaceAll(task, ''));\n            break;\n          }\n        }\n\n        // 3. default prompt\n        if (prompts.length !== text.length) {\n          prompts.push(t);\n        }\n      }\n    }\n    return prompts;\n  }\n\n  /**\n   * Post-process the output of the model to each of the task outputs.\n   * @param {string} text The text to post-process.\n   * @param {string} task The task to post-process the text for.\n   * @param {[number, number]} image_size The size of the image. height x width.\n   */\n  post_process_generation(text: string, task: string, image_size: [number, number]) {\n    const task_answer_post_processing_type = this.tasks_answer_post_processing_type.get(task) ?? 'pure_text';\n\n    // remove the special tokens\n    text = text.replaceAll('<s>', '').replaceAll('</s>', '');\n\n    let final_answer;\n    switch (task_answer_post_processing_type) {\n      case 'pure_text':\n        final_answer = text;\n        break;\n\n      case 'description_with_bboxes':\n      case 'bboxes':\n      case 'phrase_grounding':\n      case 'ocr':\n        const key = task_answer_post_processing_type === 'ocr' ? 'quad_boxes' : 'bboxes';\n        const matches = text.matchAll(this.regexes[key]);\n        const labels: string[] = [];\n        const items: number[][] = [];\n        for (const [_, label, ...locations] of matches) {\n          // Push new label, or duplicate the last label\n          labels.push(label ? label.trim() : (labels.at(-1) ?? ''));\n          items.push(\n            locations.map(\n              (x, i) =>\n                // NOTE: Add 0.5 to use the center position of the bin as the coordinate.\n                ((Number(x) + 0.5) / this.size_per_bin) * image_size[i % 2],\n            ),\n          );\n        }\n        final_answer = { labels, [key]: items };\n        break;\n\n      default:\n        throw new Error(`Task \"${task}\" (of type \"${task_answer_post_processing_type}\") not yet implemented.`);\n    }\n\n    return { [task]: final_answer };\n  }\n\n  // NOTE: images and text are switched from the python version\n  // `images` is required, `text` is optional\n  async _call(images: any, text = null, kwargs = {}) {\n    if (!images && !text) {\n      throw new Error('Either text or images must be provided');\n    }\n\n    const image_inputs = await this.image_processor(images, kwargs);\n    const text_inputs = text ? this.tokenizer(text, kwargs) : {};\n\n    return {\n      ...image_inputs,\n      ...text_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils';\nimport { AutoImageProcessor } from '../auto/image_processing_auto';\nimport { AutoTokenizer } from '../../tokenizers';\nimport { RawImage } from '../../utils/image';\nimport { count } from '../../utils/core';\n\n/**\n * Prompt with expanded image tokens for when the image is split into patches.\n * @private\n */\nfunction _prompt_split_image(\n  image_seq_len: number,\n  image_rows: number,\n  image_cols: number,\n  fake_token_around_image: string,\n  image_token: string,\n  global_img_token: string,\n) {\n  let text_split_images = '';\n  for (let n_h = 0; n_h < image_rows; ++n_h) {\n    for (let n_w = 0; n_w < image_cols; ++n_w) {\n      text_split_images +=\n        fake_token_around_image + `<row_${n_h + 1}_col_${n_w + 1}>` + image_token.repeat(image_seq_len);\n    }\n    text_split_images += '\\n';\n  }\n\n  text_split_images +=\n    `\\n${fake_token_around_image}` +\n    `${global_img_token}` +\n    image_token.repeat(image_seq_len) +\n    `${fake_token_around_image}`;\n  return text_split_images;\n}\n\n/**\n * Prompt with expanded image tokens for a single image.\n * @private\n */\nfunction _prompt_single_image(\n  image_seq_len: number,\n  fake_token_around_image: string,\n  image_token: string,\n  global_img_token: string,\n) {\n  return (\n    `${fake_token_around_image}` +\n    `${global_img_token}` +\n    image_token.repeat(image_seq_len) +\n    `${fake_token_around_image}`\n  );\n}\n\nfunction get_image_prompt_string(\n  image_rows: number,\n  image_cols: number,\n  image_seq_len: number,\n  fake_token_around_image: string,\n  image_token: string,\n  global_img_token: string,\n) {\n  if (image_rows === 0 && image_cols === 0) {\n    return _prompt_single_image(image_seq_len, fake_token_around_image, image_token, global_img_token);\n  }\n  return _prompt_split_image(\n    image_seq_len,\n    image_rows,\n    image_cols,\n    fake_token_around_image,\n    image_token,\n    global_img_token,\n  );\n}\n\nexport class Idefics3Processor extends Processor {\n  static image_processor_class = AutoImageProcessor;\n  static tokenizer_class = AutoTokenizer;\n  static uses_processor_config = true;\n\n  fake_image_token = '<fake_token_around_image>';\n  image_token = '<image>';\n  global_img_token = '<global-img>';\n\n  /**\n   *\n   * @param {string|string[]} text\n   * @param {RawImage|RawImage[]|RawImage[][]} images\n   * @returns {Promise<any>}\n   */\n  async _call(text: string | string[], images: RawImage | RawImage[] | RawImage[][], options: any = {}) {\n    options.return_row_col_info ??= true;\n\n    let image_inputs;\n\n    if (images) {\n      image_inputs = await this.image_processor(images, options);\n    }\n\n    // NOTE: We assume text is present\n    if (!Array.isArray(text)) {\n      text = [text];\n    }\n\n    const image_rows = image_inputs.rows ?? [new Array(text.length).fill(0)];\n    const image_cols = image_inputs.cols ?? [new Array(text.length).fill(0)];\n\n    const image_seq_len = this.config.image_seq_len;\n    const n_images_in_text = [];\n    const prompt_strings = [];\n    for (let i = 0; i < text.length; ++i) {\n      const sample = text[i];\n      const sample_rows = image_rows[i];\n      const sample_cols = image_cols[i];\n\n      n_images_in_text.push(count(sample, this.image_token));\n\n      // Replace the image token with fake tokens around the expanded image token sequence of length `image_seq_len`\n      const image_prompt_strings = sample_rows.map((n_rows: number, j: number) =>\n        get_image_prompt_string(\n          n_rows,\n          sample_cols[j],\n          image_seq_len,\n          this.fake_image_token,\n          this.image_token,\n          this.global_img_token,\n        ),\n      );\n\n      const split_sample = sample.split(this.image_token);\n      if (split_sample.length === 0) {\n        throw new Error('The image token should be present in the text.');\n      }\n\n      // Place in the image prompt strings where the image tokens are\n      let new_sample = split_sample[0];\n      for (let j = 0; j < image_prompt_strings.length; ++j) {\n        new_sample += image_prompt_strings[j] + split_sample[j + 1];\n      }\n      prompt_strings.push(new_sample);\n    }\n\n    const text_inputs = this.tokenizer(prompt_strings);\n\n    return {\n      ...text_inputs,\n      ...image_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { max, softmax } from '../../utils/maths.js';\n\nconst DECODE_TYPE_MAPPING = {\n  char: ['char_decode', 1],\n  bpe: ['bpe_decode', 2],\n  wp: ['wp_decode', 102],\n};\nexport class MgpstrProcessor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static image_processor_class = AutoImageProcessor;\n\n  /**\n   * @returns {import('../../tokenizers.js').MgpstrTokenizer} The character tokenizer.\n   */\n  get char_tokenizer() {\n    return this.components.char_tokenizer;\n  }\n\n  /**\n   * @returns {import('../../tokenizers.js').GPT2Tokenizer} The BPE tokenizer.\n   */\n  get bpe_tokenizer() {\n    return this.components.bpe_tokenizer;\n  }\n\n  /**\n   * @returns {import('../../tokenizers.js').BertTokenizer} The WordPiece tokenizer.\n   */\n  get wp_tokenizer() {\n    return this.components.wp_tokenizer;\n  }\n\n  /**\n   * Helper function to decode the model prediction logits.\n   * @param {import('../../utils/tensor.js').Tensor} pred_logits Model prediction logits.\n   * @param {string} format Type of model prediction. Must be one of ['char', 'bpe', 'wp'].\n   * @returns {[string[], number[]]} The decoded sentences and their confidence scores.\n   */\n  _decode_helper(pred_logits, format) {\n    if (!DECODE_TYPE_MAPPING.hasOwnProperty(format)) {\n      throw new Error(`Format ${format} is not supported.`);\n    }\n\n    const [decoder_name, eos_token] = DECODE_TYPE_MAPPING[format];\n    const decoder = this[decoder_name].bind(this);\n\n    const [batch_size, batch_max_length] = pred_logits.dims;\n    const conf_scores = [];\n    const all_ids = [];\n\n    /** @type {number[][][]} */\n    const pred_logits_list = pred_logits.tolist();\n    for (let i = 0; i < batch_size; ++i) {\n      const logits = pred_logits_list[i];\n      const ids = [];\n      const scores = [];\n\n      // Start and index=1 to skip the first token\n      for (let j = 1; j < batch_max_length; ++j) {\n        // NOTE: == to match bigint and number\n        const [max_prob, max_prob_index] = max(softmax(logits[j]));\n        scores.push(max_prob);\n        if (max_prob_index == eos_token) {\n          break;\n        }\n        ids.push(max_prob_index);\n      }\n\n      const confidence_score = scores.length > 0 ? scores.reduce((a, b) => a * b, 1) : 0;\n\n      all_ids.push(ids);\n      conf_scores.push(confidence_score);\n    }\n\n    const decoded = decoder(all_ids);\n    return [decoded, conf_scores];\n  }\n\n  /**\n   * Convert a list of lists of char token ids into a list of strings by calling char tokenizer.\n   * @param {number[][]} sequences List of tokenized input ids.\n   * @returns {string[]} The list of char decoded sentences.\n   */\n  char_decode(sequences) {\n    return this.char_tokenizer.batch_decode(sequences).map((str) => str.replaceAll(' ', ''));\n  }\n\n  /**\n   * Convert a list of lists of BPE token ids into a list of strings by calling BPE tokenizer.\n   * @param {number[][]} sequences List of tokenized input ids.\n   * @returns {string[]} The list of BPE decoded sentences.\n   */\n  bpe_decode(sequences) {\n    return this.bpe_tokenizer.batch_decode(sequences);\n  }\n\n  /**\n   * Convert a list of lists of word piece token ids into a list of strings by calling word piece tokenizer.\n   * @param {number[][]} sequences List of tokenized input ids.\n   * @returns {string[]} The list of wp decoded sentences.\n   */\n  wp_decode(sequences) {\n    return this.wp_tokenizer.batch_decode(sequences).map((str) => str.replaceAll(' ', ''));\n  }\n\n  /**\n   * Convert a list of lists of token ids into a list of strings by calling decode.\n   * @param {import('../../utils/tensor.js').Tensor[]} sequences List of tokenized input ids.\n   * @returns {{generated_text: string[], scores: number[], char_preds: string[], bpe_preds: string[], wp_preds: string[]}}\n   * Dictionary of all the outputs of the decoded results.\n   * - generated_text: The final results after fusion of char, bpe, and wp.\n   * - scores: The final scores after fusion of char, bpe, and wp.\n   * - char_preds: The list of character decoded sentences.\n   * - bpe_preds: The list of BPE decoded sentences.\n   * - wp_preds: The list of wp decoded sentences.\n   */\n  // @ts-expect-error The type of this method is not compatible with the one\n  // in the base class. It might be a good idea to fix this.\n  batch_decode([char_logits, bpe_logits, wp_logits]) {\n    const [char_preds, char_scores] = this._decode_helper(char_logits, 'char');\n    const [bpe_preds, bpe_scores] = this._decode_helper(bpe_logits, 'bpe');\n    const [wp_preds, wp_scores] = this._decode_helper(wp_logits, 'wp');\n\n    const generated_text = [];\n    const scores = [];\n    for (let i = 0; i < char_preds.length; ++i) {\n      const [max_score, max_score_index] = max([char_scores[i], bpe_scores[i], wp_scores[i]]);\n      generated_text.push([char_preds[i], bpe_preds[i], wp_preds[i]][max_score_index]);\n      scores.push(max_score);\n    }\n\n    return {\n      generated_text,\n      scores,\n      char_preds,\n      bpe_preds,\n      wp_preds,\n    };\n  }\n  /** @type {typeof Processor.from_pretrained} */\n  static async from_pretrained(...args) {\n    const base = await super.from_pretrained(...args);\n\n    // Load Transformers.js-compatible versions of the BPE and WordPiece tokenizers\n    const bpe_tokenizer = await AutoTokenizer.from_pretrained('Xenova/gpt2'); // openai-community/gpt2\n    const wp_tokenizer = await AutoTokenizer.from_pretrained('Xenova/bert-base-uncased'); // google-bert/bert-base-uncased\n\n    // Update components\n    base.components = {\n      image_processor: base.image_processor,\n      char_tokenizer: base.tokenizer,\n      bpe_tokenizer: bpe_tokenizer,\n      wp_tokenizer: wp_tokenizer,\n    };\n    return base;\n  }\n\n  async _call(images, text = null) {\n    const result = await this.image_processor(images);\n\n    if (text) {\n      result.labels = this.tokenizer(text).input_ids;\n    }\n\n    return result;\n  }\n}\n","export * from './audio_spectrogram_transformer/feature_extraction_audio_spectrogram_transformer';\nexport * from './clap/feature_extraction_clap';\nexport * from './moonshine/feature_extraction_moonshine';\nexport * from './pyannote/feature_extraction_pyannote';\nexport * from './seamless_m4t/feature_extraction_seamless_m4t';\nexport * from './speecht5/feature_extraction_speecht5';\nexport * from './wav2vec2/feature_extraction_wav2vec2';\nexport * from './wespeaker/feature_extraction_wespeaker';\nexport * from './whisper/feature_extraction_whisper';\n\n// For legacy support, ImageFeatureExtractor is an alias for ImageProcessor\nexport { ImageProcessor as ImageFeatureExtractor } from '../base/image_processors_utils';\n","import { FEATURE_EXTRACTOR_NAME } from '../utils/constants';\nimport { Callable } from '../utils/generic';\nimport { getModelJSON } from '../utils/hub';\nimport { PretrainedOptions } from '../utils/hub';\ninterface FeatureExtractorConfig {\n  feature_extractor_type: string;\n  [key: string]: any; // Allow for additional properties\n}\n\n/**\n * Base class for feature extractors.\n */\nexport class FeatureExtractor extends Callable {\n  protected config: FeatureExtractorConfig;\n\n  /**\n   * Constructs a new FeatureExtractor instance.\n   *\n   * @param {Object} config The configuration for the feature extractor.\n   */\n  constructor(config: FeatureExtractorConfig) {\n    super();\n    this.config = config;\n  }\n\n  /**\n   * Instantiate one of the feature extractor classes of the library from a pretrained model.\n   *\n   * The feature extractor class to instantiate is selected based on the `feature_extractor_type` property of\n   * the config object (either passed as an argument or loaded from `pretrained_model_name_or_path` if possible)\n   *\n   * @param {string} pretrained_model_name_or_path The name or path of the pretrained model. Can be either:\n   * - A string, the *model id* of a pretrained feature_extractor hosted inside a model repo on huggingface.co.\n   *   Valid model ids can be located at the root-level, like `bert-base-uncased`, or namespaced under a\n   *   user or organization name, like `dbmdz/bert-base-german-cased`.\n   * - A path to a *directory* containing feature_extractor files, e.g., `./my_model_directory/`.\n   * @param {import('../utils/hub.js').PretrainedOptions} options Additional options for loading the feature_extractor.\n   *\n   * @returns {Promise<FeatureExtractor>} A new instance of the Feature Extractor class.\n   */\n  static async from_pretrained(pretrained_model_name_or_path: string, options: PretrainedOptions) {\n    const config = await getModelJSON(pretrained_model_name_or_path, FEATURE_EXTRACTOR_NAME, true, options);\n    return new this(config);\n  }\n}\n\n/**\n * Helper function to validate audio inputs.\n * @param {any} audio The audio data.\n * @param {string} feature_extractor The name of the feature extractor.\n * @private\n */\nexport function validate_audio_inputs(audio: any, feature_extractor: string) {\n  if (!(audio instanceof Float32Array || audio instanceof Float64Array)) {\n    throw new Error(\n      `${feature_extractor} expects input to be a Float32Array or a Float64Array, but got ${audio?.constructor?.name ?? typeof audio} instead. ` +\n        `If using the feature extractor directly, remember to use \\`read_audio(url, sampling_rate)\\` to obtain the raw audio data of the file/url.`,\n    );\n  }\n}\n","/**\n * @file Helper module for audio processing.\n *\n * These functions and classes are only used internally,\n * meaning an end-user shouldn't need to access anything here.\n *\n * @module utils/audio\n */\n\nimport { getFile } from './hub';\nimport { FFT, max } from './maths';\nimport { calculateReflectOffset, saveBlob } from './core';\nimport { Tensor, matmul } from './tensor';\nimport { apis } from '../env';\n\n/**\n * Helper function to read audio from a path/URL.\n * @param {string|URL} url The path/URL to load the audio from.\n * @param {number} sampling_rate The sampling rate to use when decoding the audio.\n * @returns {Promise<Float32Array>} The decoded audio as a `Float32Array`.\n */\nexport async function read_audio(url: string | URL, sampling_rate: number) {\n  if (typeof AudioContext === 'undefined') {\n    // Running in node or an environment without AudioContext\n    throw Error(\n      'Unable to load audio from path/URL since `AudioContext` is not available in your environment. ' +\n        'Instead, audio data should be passed directly to the pipeline/processor. ' +\n        'For more information and some example code, see https://huggingface.co/docs/transformers.js/guides/node-audio-processing.',\n    );\n  }\n\n  const response = await (await getFile(url)).arrayBuffer();\n  const audioCTX = new AudioContext({ sampleRate: sampling_rate });\n  if (typeof sampling_rate === 'undefined') {\n    console.warn(`No sampling rate provided, using default of ${audioCTX.sampleRate}Hz.`);\n  }\n  const decoded = await audioCTX.decodeAudioData(response);\n\n  /** @type {Float32Array} */\n  let audio;\n\n  // We now replicate HuggingFace's `ffmpeg_read` method:\n  if (decoded.numberOfChannels === 2) {\n    // When downmixing a stereo audio file to mono using the -ac 1 option in FFmpeg,\n    // the audio signal is summed across both channels to create a single mono channel.\n    // However, if the audio is at full scale (i.e. the highest possible volume level),\n    // the summing of the two channels can cause the audio signal to clip or distort.\n\n    // To prevent this clipping, FFmpeg applies a scaling factor of 1/sqrt(2) (~ 0.707)\n    // to the audio signal before summing the two channels. This scaling factor ensures\n    // that the combined audio signal will not exceed the maximum possible level, even\n    // if both channels are at full scale.\n\n    // After applying this scaling factor, the audio signal from both channels is summed\n    // to create a single mono channel. It's worth noting that this scaling factor is\n    // only applied when downmixing stereo audio to mono using the -ac 1 option in FFmpeg.\n    // If you're using a different downmixing method, or if you're not downmixing the\n    // audio at all, this scaling factor may not be needed.\n    const SCALING_FACTOR = Math.sqrt(2);\n\n    const left = decoded.getChannelData(0);\n    const right = decoded.getChannelData(1);\n\n    audio = new Float32Array(left.length);\n    for (let i = 0; i < decoded.length; ++i) {\n      audio[i] = (SCALING_FACTOR * (left[i] + right[i])) / 2;\n    }\n  } else {\n    // If the audio is not stereo, we can just use the first channel:\n    audio = decoded.getChannelData(0);\n  }\n\n  return audio;\n}\n\n/**\n * Helper function to generate windows that are special cases of the generalized cosine window.\n * See https://www.mathworks.com/help/signal/ug/generalized-cosine-windows.html for more information.\n * @param {number} M Number of points in the output window. If zero or less, an empty array is returned.\n * @param {number} a_0 Offset for the generalized cosine window.\n * @returns {Float64Array} The generated window.\n */\nfunction generalized_cosine_window(M: number, a_0: number) {\n  if (M < 1) {\n    return new Float64Array();\n  }\n  if (M === 1) {\n    return new Float64Array([1]);\n  }\n\n  const a_1 = 1 - a_0;\n  const factor = (2 * Math.PI) / (M - 1);\n\n  const cos_vals = new Float64Array(M);\n  for (let i = 0; i < M; ++i) {\n    cos_vals[i] = a_0 - a_1 * Math.cos(i * factor);\n  }\n  return cos_vals;\n}\n\n/**\n * Generates a Hanning window of length M.\n * See https://numpy.org/doc/stable/reference/generated/numpy.hanning.html for more information.\n *\n * @param {number} M The length of the Hanning window to generate.\n * @returns {Float64Array} The generated Hanning window.\n */\nexport function hanning(M: number) {\n  return generalized_cosine_window(M, 0.5);\n}\n\n/**\n * Generates a Hamming window of length M.\n * See https://numpy.org/doc/stable/reference/generated/numpy.hamming.html for more information.\n *\n * @param {number} M The length of the Hamming window to generate.\n * @returns {Float64Array} The generated Hamming window.\n */\nexport function hamming(M: number) {\n  return generalized_cosine_window(M, 0.54);\n}\n\nconst HERTZ_TO_MEL_MAPPING: { [key: string]: (freq: number) => number } = {\n  htk: (freq: number) => 2595.0 * Math.log10(1.0 + freq / 700.0),\n  kaldi: (freq: number) => 1127.0 * Math.log(1.0 + freq / 700.0),\n  slaney: (freq: number, min_log_hertz = 1000.0, min_log_mel = 15.0, logstep = 27.0 / Math.log(6.4)) =>\n    freq >= min_log_hertz ? min_log_mel + Math.log(freq / min_log_hertz) * logstep : (3.0 * freq) / 200.0,\n};\n\n/**\n * @template {Float32Array|Float64Array|number} T\n * @param {T} freq\n * @param {string} [mel_scale]\n * @returns {T}\n */\nfunction hertz_to_mel<T extends Float32Array | Float64Array | number>(freq: T, mel_scale = 'htk') {\n  const fn = HERTZ_TO_MEL_MAPPING[mel_scale];\n  if (!fn) {\n    throw new Error('mel_scale should be one of \"htk\", \"slaney\" or \"kaldi\".');\n  }\n\n  return typeof freq === 'number' ? fn(freq) : freq.map((x: number) => fn(x));\n}\n\nconst MEL_TO_HERTZ_MAPPING: { [key: string]: (mels: number) => number } = {\n  htk: (mels: number) => 700.0 * (10.0 ** (mels / 2595.0) - 1.0),\n  kaldi: (mels: number) => 700.0 * (Math.exp(mels / 1127.0) - 1.0),\n  slaney: (mels: number, min_log_hertz = 1000.0, min_log_mel = 15.0, logstep = Math.log(6.4) / 27.0) =>\n    mels >= min_log_mel ? min_log_hertz * Math.exp(logstep * (mels - min_log_mel)) : (200.0 * mels) / 3.0,\n};\n\n/**\n * @template {Float32Array|Float64Array|number} T\n * @param {T} mels\n * @param {string} [mel_scale]\n * @returns {T}\n */\nfunction mel_to_hertz<T extends Float32Array | Float64Array | number>(mels: T, mel_scale = 'htk') {\n  const fn = MEL_TO_HERTZ_MAPPING[mel_scale];\n  if (!fn) {\n    throw new Error('mel_scale should be one of \"htk\", \"slaney\" or \"kaldi\".');\n  }\n\n  return typeof mels === 'number' ? fn(mels) : mels.map((x) => fn(x));\n}\n\n/**\n * Creates a triangular filter bank.\n *\n * Adapted from torchaudio and librosa.\n *\n * @param {Float64Array} fft_freqs Discrete frequencies of the FFT bins in Hz, of shape `(num_frequency_bins,)`.\n * @param {Float64Array} filter_freqs Center frequencies of the triangular filters to create, in Hz, of shape `(num_mel_filters,)`.\n * @returns {number[][]} of shape `(num_frequency_bins, num_mel_filters)`.\n */\nfunction _create_triangular_filter_bank(fft_freqs: Float64Array, filter_freqs: Float64Array) {\n  const filter_diff = Float64Array.from(\n    { length: filter_freqs.length - 1 },\n    (_, i) => filter_freqs[i + 1] - filter_freqs[i],\n  );\n\n  const slopes = Array.from(\n    {\n      length: fft_freqs.length,\n    },\n    () => new Array(filter_freqs.length),\n  );\n\n  for (let j = 0; j < fft_freqs.length; ++j) {\n    const slope = slopes[j];\n    for (let i = 0; i < filter_freqs.length; ++i) {\n      slope[i] = filter_freqs[i] - fft_freqs[j];\n    }\n  }\n\n  const numFreqs = filter_freqs.length - 2;\n  const ret = Array.from({ length: numFreqs }, () => new Array(fft_freqs.length));\n\n  for (let j = 0; j < fft_freqs.length; ++j) {\n    // 201\n    const slope = slopes[j];\n    for (let i = 0; i < numFreqs; ++i) {\n      // 80\n      const down = -slope[i] / filter_diff[i];\n      const up = slope[i + 2] / filter_diff[i + 1];\n      ret[i][j] = Math.max(0, Math.min(down, up));\n    }\n  }\n  return ret;\n}\n\n/**\n * Return evenly spaced numbers over a specified interval.\n * @param {number} start The starting value of the sequence.\n * @param {number} end The end value of the sequence.\n * @param {number} num Number of samples to generate.\n * @returns `num` evenly spaced samples, calculated over the interval `[start, stop]`.\n */\nfunction linspace(start: number, end: number, num: number) {\n  const step = (end - start) / (num - 1);\n  return Float64Array.from({ length: num }, (_, i) => start + step * i);\n}\n\n/**\n * Creates a frequency bin conversion matrix used to obtain a mel spectrogram. This is called a *mel filter bank*, and\n * various implementation exist, which differ in the number of filters, the shape of the filters, the way the filters\n * are spaced, the bandwidth of the filters, and the manner in which the spectrum is warped. The goal of these\n * features is to approximate the non-linear human perception of the variation in pitch with respect to the frequency.\n * @param {number} num_frequency_bins Number of frequencies used to compute the spectrogram (should be the same as in `stft`).\n * @param {number} num_mel_filters Number of mel filters to generate.\n * @param {number} min_frequency Lowest frequency of interest in Hz.\n * @param {number} max_frequency Highest frequency of interest in Hz. This should not exceed `sampling_rate / 2`.\n * @param {number} sampling_rate Sample rate of the audio waveform.\n * @param {string} [norm] If `\"slaney\"`, divide the triangular mel weights by the width of the mel band (area normalization).\n * @param {string} [mel_scale] The mel frequency scale to use, `\"htk\"` or `\"slaney\"`.\n * @param {boolean} [triangularize_in_mel_space] If this option is enabled, the triangular filter is applied in mel space rather than frequency space.\n * This should be set to `true` in order to get the same results as `torchaudio` when computing mel filters.\n * @returns {number[][]} Triangular filter bank matrix, which is a 2D array of shape (`num_frequency_bins`, `num_mel_filters`).\n * This is a projection matrix to go from a spectrogram to a mel spectrogram.\n */\nexport function mel_filter_bank(\n  num_frequency_bins: number,\n  num_mel_filters: number,\n  min_frequency: number,\n  max_frequency: number,\n  sampling_rate: number,\n  norm: string | null = null,\n  mel_scale = 'htk',\n  triangularize_in_mel_space = false,\n) {\n  if (norm !== null && norm !== 'slaney') {\n    throw new Error('norm must be one of null or \"slaney\"');\n  }\n\n  const mel_min: any = hertz_to_mel(min_frequency, mel_scale);\n  const mel_max: any = hertz_to_mel(max_frequency, mel_scale);\n  const mel_freqs: any = linspace(mel_min, mel_max, num_mel_filters + 2);\n\n  let filter_freqs: any = mel_to_hertz(mel_freqs, mel_scale);\n  let fft_freqs: any; // frequencies of FFT bins in Hz\n\n  if (triangularize_in_mel_space) {\n    const fft_bin_width = sampling_rate / (num_frequency_bins * 2);\n    fft_freqs = hertz_to_mel(\n      Float64Array.from({ length: num_frequency_bins }, (_, i) => i * fft_bin_width),\n      mel_scale,\n    );\n    filter_freqs = mel_freqs;\n  } else {\n    fft_freqs = linspace(0, Math.floor(sampling_rate / 2), num_frequency_bins);\n  }\n\n  const mel_filters = _create_triangular_filter_bank(fft_freqs, filter_freqs);\n\n  if (norm !== null && norm === 'slaney') {\n    // Slaney-style mel is scaled to be approx constant energy per channel\n    for (let i = 0; i < num_mel_filters; ++i) {\n      const filter = mel_filters[i];\n      const enorm = 2.0 / (filter_freqs[i + 2] - filter_freqs[i]);\n      for (let j = 0; j < num_frequency_bins; ++j) {\n        // Apply this enorm to all frequency bins\n        filter[j] *= enorm;\n      }\n    }\n  }\n\n  // TODO warn if there is a zero row\n\n  return mel_filters;\n}\n\n/**\n * @template {Float32Array|Float64Array} T\n * Pads an array with a reflected version of itself on both ends.\n * @param {T} array The array to pad.\n * @param {number} left The amount of padding to add to the left.\n * @param {number} right The amount of padding to add to the right.\n * @returns {T} The padded array.\n */\nfunction padReflect<T extends Float32Array | Float64Array>(array: T, left: number, right: number) {\n  // @ts-ignore\n  const padded = new array.constructor(array.length + left + right);\n  const w = array.length - 1;\n\n  for (let i = 0; i < array.length; ++i) {\n    padded[left + i] = array[i];\n  }\n\n  for (let i = 1; i <= left; ++i) {\n    padded[left - i] = array[calculateReflectOffset(i, w)];\n  }\n\n  for (let i = 1; i <= right; ++i) {\n    padded[w + left + i] = array[calculateReflectOffset(w - i, w)];\n  }\n\n  return padded;\n}\n\n/**\n * Helper function to compute `amplitude_to_db` and `power_to_db`.\n * @template {Float32Array|Float64Array} T\n * @param {T} spectrogram\n * @param {number} factor\n * @param {number} reference\n * @param {number} min_value\n * @param {number} db_range\n * @returns {T}\n */\nfunction _db_conversion_helper<T extends Float32Array | Float64Array>(\n  spectrogram: T,\n  factor: number,\n  reference: number,\n  min_value: number,\n  db_range: number | null,\n) {\n  if (reference <= 0) {\n    throw new Error('reference must be greater than zero');\n  }\n\n  if (min_value <= 0) {\n    throw new Error('min_value must be greater than zero');\n  }\n\n  reference = Math.max(min_value, reference);\n\n  const logReference = Math.log10(reference);\n  for (let i = 0; i < spectrogram.length; ++i) {\n    spectrogram[i] = factor * Math.log10(Math.max(min_value, spectrogram[i]) - logReference);\n  }\n\n  if (db_range !== null) {\n    if (db_range <= 0) {\n      throw new Error('db_range must be greater than zero');\n    }\n    const maxValue = Number(max(spectrogram)[0]) - db_range;\n    for (let i = 0; i < spectrogram.length; ++i) {\n      spectrogram[i] = Math.max(spectrogram[i], maxValue);\n    }\n  }\n\n  return spectrogram;\n}\n\n/**\n * Converts an amplitude spectrogram to the decibel scale. This computes `20 * log10(spectrogram / reference)`,\n * using basic logarithm properties for numerical stability. NOTE: Operates in-place.\n *\n * The motivation behind applying the log function on the (mel) spectrogram is that humans do not hear loudness on a\n * linear scale. Generally to double the perceived volume of a sound we need to put 8 times as much energy into it.\n * This means that large variations in energy may not sound all that different if the sound is loud to begin with.\n * This compression operation makes the (mel) spectrogram features match more closely what humans actually hear.\n *\n * @template {Float32Array|Float64Array} T\n * @param {T} spectrogram The input amplitude (mel) spectrogram.\n * @param {number} [reference=1.0] Sets the input spectrogram value that corresponds to 0 dB.\n * For example, use `np.max(spectrogram)` to set the loudest part to 0 dB. Must be greater than zero.\n * @param {number} [min_value=1e-5] The spectrogram will be clipped to this minimum value before conversion to decibels,\n * to avoid taking `log(0)`. The default of `1e-5` corresponds to a minimum of -100 dB. Must be greater than zero.\n * @param {number} [db_range=null] Sets the maximum dynamic range in decibels. For example, if `db_range = 80`, the\n * difference between the peak value and the smallest value will never be more than 80 dB. Must be greater than zero.\n * @returns {T} The modified spectrogram in decibels.\n */\nfunction amplitude_to_db(spectrogram: Float32Array | Float64Array, reference = 1.0, min_value = 1e-5, db_range = null) {\n  return _db_conversion_helper(spectrogram, 20.0, reference, min_value, db_range);\n}\n\n/**\n * Converts a power spectrogram to the decibel scale. This computes `10 * log10(spectrogram / reference)`,\n * using basic logarithm properties for numerical stability. NOTE: Operates in-place.\n *\n * The motivation behind applying the log function on the (mel) spectrogram is that humans do not hear loudness on a\n * linear scale. Generally to double the perceived volume of a sound we need to put 8 times as much energy into it.\n * This means that large variations in energy may not sound all that different if the sound is loud to begin with.\n * This compression operation makes the (mel) spectrogram features match more closely what humans actually hear.\n *\n * Based on the implementation of `librosa.power_to_db`.\n *\n * @template {Float32Array|Float64Array} T\n * @param {T} spectrogram The input power (mel) spectrogram. Note that a power spectrogram has the amplitudes squared!\n * @param {number} [reference=1.0] Sets the input spectrogram value that corresponds to 0 dB.\n * For example, use `np.max(spectrogram)` to set the loudest part to 0 dB. Must be greater than zero.\n * @param {number} [min_value=1e-10] The spectrogram will be clipped to this minimum value before conversion to decibels,\n * to avoid taking `log(0)`. The default of `1e-10` corresponds to a minimum of -100 dB. Must be greater than zero.\n * @param {number} [db_range=null] Sets the maximum dynamic range in decibels. For example, if `db_range = 80`, the\n * difference between the peak value and the smallest value will never be more than 80 dB. Must be greater than zero.\n * @returns {T} The modified spectrogram in decibels.\n */\nfunction power_to_db(\n  spectrogram: Float32Array | Float64Array,\n  reference = 1.0,\n  min_value = 1e-10,\n  db_range: number | null = null,\n) {\n  return _db_conversion_helper(spectrogram, 10.0, reference, min_value, db_range);\n}\n\n/**\n * Calculates a spectrogram over one waveform using the Short-Time Fourier Transform.\n *\n * This function can create the following kinds of spectrograms:\n *   - amplitude spectrogram (`power = 1.0`)\n *   - power spectrogram (`power = 2.0`)\n *   - complex-valued spectrogram (`power = None`)\n *   - log spectrogram (use `log_mel` argument)\n *   - mel spectrogram (provide `mel_filters`)\n *   - log-mel spectrogram (provide `mel_filters` and `log_mel`)\n *\n * In this implementation, the window is assumed to be zero-padded to have the same size as the analysis frame.\n * A padded window can be obtained from `window_function()`. The FFT input buffer may be larger than the analysis frame,\n * typically the next power of two.\n *\n * @param {Float32Array|Float64Array} waveform The input waveform of shape `(length,)`. This must be a single real-valued, mono waveform.\n * @param {Float32Array|Float64Array} window The windowing function to apply of shape `(frame_length,)`, including zero-padding if necessary. The actual window length may be\n * shorter than `frame_length`, but we're assuming the array has already been zero-padded.\n * @param {number} frame_length The length of the analysis frames in samples (a.k.a., `fft_length`).\n * @param {number} hop_length The stride between successive analysis frames in samples.\n * @param {Object} options\n * @param {number} [options.fft_length=null] The size of the FFT buffer in samples. This determines how many frequency bins the spectrogram will have.\n * For optimal speed, this should be a power of two. If `null`, uses `frame_length`.\n * @param {number} [options.power=1.0] If 1.0, returns the amplitude spectrogram. If 2.0, returns the power spectrogram. If `null`, returns complex numbers.\n * @param {boolean} [options.center=true] Whether to pad the waveform so that frame `t` is centered around time `t * hop_length`. If `false`, frame\n * `t` will start at time `t * hop_length`.\n * @param {string} [options.pad_mode=\"reflect\"] Padding mode used when `center` is `true`. Possible values are: `\"constant\"` (pad with zeros),\n * `\"edge\"` (pad with edge values), `\"reflect\"` (pads with mirrored values).\n * @param {boolean} [options.onesided=true] If `true`, only computes the positive frequencies and returns a spectrogram containing `fft_length // 2 + 1`\n * frequency bins. If `false`, also computes the negative frequencies and returns `fft_length` frequency bins.\n * @param {number} [options.preemphasis=null] Coefficient for a low-pass filter that applies pre-emphasis before the DFT.\n * @param {number[][]} [options.mel_filters=null] The mel filter bank of shape `(num_freq_bins, num_mel_filters)`.\n * If supplied, applies this filter bank to create a mel spectrogram.\n * @param {number} [options.mel_floor=1e-10] Minimum value of mel frequency banks.\n * @param {string} [options.log_mel=null] How to convert the spectrogram to log scale. Possible options are:\n * `null` (don't convert), `\"log\"` (take the natural logarithm) `\"log10\"` (take the base-10 logarithm), `\"dB\"` (convert to decibels).\n * Can only be used when `power` is not `null`.\n * @param {number} [options.reference=1.0] Sets the input spectrogram value that corresponds to 0 dB. For example, use `max(spectrogram)[0]` to set\n * the loudest part to 0 dB. Must be greater than zero.\n * @param {number} [options.min_value=1e-10] The spectrogram will be clipped to this minimum value before conversion to decibels, to avoid taking `log(0)`.\n * For a power spectrogram, the default of `1e-10` corresponds to a minimum of -100 dB. For an amplitude spectrogram, the value `1e-5` corresponds to -100 dB.\n * Must be greater than zero.\n * @param {number} [options.db_range=null] Sets the maximum dynamic range in decibels. For example, if `db_range = 80`, the difference between the\n * peak value and the smallest value will never be more than 80 dB. Must be greater than zero.\n * @param {boolean} [options.remove_dc_offset=null] Subtract mean from waveform on each frame, applied before pre-emphasis. This should be set to `true` in\n * order to get the same results as `torchaudio.compliance.kaldi.fbank` when computing mel filters.\n * @param {number} [options.max_num_frames=null] If provided, limits the number of frames to compute to this value.\n * @param {number} [options.min_num_frames=null] If provided, ensures the number of frames to compute is at least this value.\n * @param {boolean} [options.do_pad=true] If `true`, pads the output spectrogram to have `max_num_frames` frames.\n * @param {boolean} [options.transpose=false] If `true`, the returned spectrogram will have shape `(num_frames, num_frequency_bins/num_mel_filters)`. If `false`, the returned spectrogram will have shape `(num_frequency_bins/num_mel_filters, num_frames)`.\n * @returns {Promise<Tensor>} Spectrogram of shape `(num_frequency_bins, length)` (regular spectrogram) or shape `(num_mel_filters, length)` (mel spectrogram).\n */\nexport async function spectrogram(\n  waveform: Float32Array | Float64Array,\n  window: Float32Array | Float64Array,\n  frame_length: number,\n  hop_length: number,\n  {\n    fft_length = null as number | null,\n    power = 1.0,\n    center = true,\n    pad_mode = 'reflect',\n    onesided = true,\n    preemphasis = null,\n    mel_filters = null as number[][] | null,\n    mel_floor = 1e-10,\n    log_mel = null,\n    reference = 1.0,\n    min_value = 1e-10,\n    db_range = null,\n    remove_dc_offset = null,\n\n    // Custom parameters for efficiency reasons\n    min_num_frames = null,\n    max_num_frames = null,\n    do_pad = true,\n    transpose = false,\n  } = {},\n) {\n  const window_length = window.length;\n  if (fft_length === null) {\n    fft_length = frame_length;\n  }\n  if (frame_length > fft_length) {\n    throw Error(`frame_length (${frame_length}) may not be larger than fft_length (${fft_length})`);\n  }\n\n  if (window_length !== frame_length) {\n    throw new Error(`Length of the window (${window_length}) must equal frame_length (${frame_length})`);\n  }\n\n  if (hop_length <= 0) {\n    throw new Error('hop_length must be greater than zero');\n  }\n\n  if (power === null && mel_filters !== null) {\n    throw new Error(\n      'You have provided `mel_filters` but `power` is `None`. Mel spectrogram computation is not yet supported for complex-valued spectrogram. ' +\n        'Specify `power` to fix this issue.',\n    );\n  }\n\n  if (center) {\n    if (pad_mode !== 'reflect') {\n      throw new Error(`pad_mode=\"${pad_mode}\" not implemented yet.`);\n    }\n    const half_window = Math.floor((fft_length - 1) / 2) + 1;\n    waveform = padReflect(waveform, half_window, half_window);\n  }\n\n  // split waveform into frames of frame_length size\n  let num_frames = Math.floor(1 + Math.floor((waveform.length - frame_length) / hop_length));\n  if (min_num_frames !== null && num_frames < min_num_frames) {\n    num_frames = min_num_frames;\n  }\n  const num_frequency_bins = onesided ? Math.floor(fft_length / 2) + 1 : fft_length;\n\n  let d1 = num_frames;\n  let d1Max = num_frames;\n\n  // If maximum number of frames is provided, we must either pad or truncate\n  if (max_num_frames !== null) {\n    if (max_num_frames > num_frames) {\n      // input is too short, so we pad\n      if (do_pad) {\n        d1Max = max_num_frames;\n      }\n    } else {\n      // input is too long, so we truncate\n      d1Max = d1 = max_num_frames;\n    }\n  }\n\n  // Preallocate arrays to store output.\n  const fft = new FFT(fft_length);\n  const inputBuffer = new Float64Array(fft_length);\n  const outputBuffer = new Float64Array(fft.outputBufferSize);\n  const transposedMagnitudeData = new Float32Array(num_frequency_bins * d1Max);\n\n  for (let i = 0; i < d1; ++i) {\n    // Populate buffer with waveform data\n    const offset = i * hop_length;\n    const buffer_size = Math.min(waveform.length - offset, frame_length);\n    if (buffer_size !== frame_length) {\n      // The full buffer is not needed, so we need to reset it (avoid overflow from previous iterations)\n      // NOTE: We don't need to reset the buffer if it's full since we overwrite the first\n      // `frame_length` values and the rest (`fft_length - frame_length`) remains zero.\n      inputBuffer.fill(0, 0, frame_length);\n    }\n\n    for (let j = 0; j < buffer_size; ++j) {\n      inputBuffer[j] = waveform[offset + j];\n    }\n\n    if (remove_dc_offset) {\n      let sum = 0;\n      for (let j = 0; j < buffer_size; ++j) {\n        sum += inputBuffer[j];\n      }\n      const mean = sum / buffer_size;\n      for (let j = 0; j < buffer_size; ++j) {\n        inputBuffer[j] -= mean;\n      }\n    }\n\n    if (preemphasis !== null) {\n      // Done in reverse to avoid copies and distructive modification\n      for (let j = buffer_size - 1; j >= 1; --j) {\n        inputBuffer[j] -= preemphasis * inputBuffer[j - 1];\n      }\n      inputBuffer[0] *= 1 - preemphasis;\n    }\n\n    // Apply window function\n    for (let j = 0; j < window.length; ++j) {\n      inputBuffer[j] *= window[j];\n    }\n\n    fft.realTransform(outputBuffer, inputBuffer);\n\n    // compute magnitudes\n    for (let j = 0; j < num_frequency_bins; ++j) {\n      const j2 = j << 1;\n\n      // NOTE: We transpose the data here to avoid doing it later\n      transposedMagnitudeData[j * d1Max + i] = outputBuffer[j2] ** 2 + outputBuffer[j2 + 1] ** 2;\n    }\n  }\n\n  if (power !== null && power !== 2) {\n    // slight optimization to not sqrt\n    const pow = 2 / power; // we use 2 since we already squared\n    for (let i = 0; i < transposedMagnitudeData.length; ++i) {\n      transposedMagnitudeData[i] **= pow;\n    }\n  }\n\n  if (!mel_filters) {\n    throw new Error('mel_filters must be provided');\n  }\n  const num_mel_filters = mel_filters.length;\n\n  // Perform matrix multiplication:\n  // mel_spec = mel_filters @ magnitudes.T\n  //  - mel_filters.shape=(80, 201)\n  //  - magnitudes.shape=(3000, 201) => magnitudes.T.shape=(201, 3000)\n  //  - mel_spec.shape=(80, 3000)\n  let mel_spec = await matmul(\n    // TODO: Make `mel_filters` a Tensor during initialization\n    new Tensor('float32', mel_filters.flat(), [num_mel_filters, num_frequency_bins] as [number, number]),\n    new Tensor('float32', transposedMagnitudeData, [num_frequency_bins, d1Max] as [number, number]),\n  );\n  if (transpose) {\n    mel_spec = mel_spec.transpose(1, 0);\n  }\n\n  const mel_spec_data = /** @type {Float32Array} */ mel_spec.data;\n  for (let i = 0; i < mel_spec_data.length; ++i) {\n    mel_spec_data[i] = Math.max(mel_floor, mel_spec_data[i]);\n  }\n\n  if (power !== null && log_mel !== null) {\n    const o = Math.min(mel_spec_data.length, d1 * num_mel_filters);\n    // NOTE: operates in-place\n    switch (log_mel) {\n      case 'log':\n        for (let i = 0; i < o; ++i) {\n          mel_spec_data[i] = Math.log(mel_spec_data[i]);\n        }\n        break;\n      case 'log10':\n        for (let i = 0; i < o; ++i) {\n          mel_spec_data[i] = Math.log10(mel_spec_data[i]);\n        }\n        break;\n      case 'dB':\n        if (power === 1.0) {\n          amplitude_to_db(mel_spec_data, reference, min_value, db_range);\n        } else if (power === 2.0) {\n          power_to_db(mel_spec_data, reference, min_value, db_range);\n        } else {\n          throw new Error(`Cannot use log_mel option '${log_mel}' with power ${power}`);\n        }\n        break;\n      default:\n        throw new Error(`log_mel must be one of null, 'log', 'log10' or 'dB'. Got '${log_mel}'`);\n    }\n  }\n\n  return mel_spec;\n}\n\n/**\n * Returns an array containing the specified window.\n * @param {number} window_length The length of the window in samples.\n * @param {string} name The name of the window function.\n * @param {Object} options Additional options.\n * @param {boolean} [options.periodic=true] Whether the window is periodic or symmetric.\n * @param {number} [options.frame_length=null] The length of the analysis frames in samples.\n * Provide a value for `frame_length` if the window is smaller than the frame length, so that it will be zero-padded.\n * @param {boolean} [options.center=true] Whether to center the window inside the FFT buffer. Only used when `frame_length` is provided.\n * @returns {Float64Array} The window of shape `(window_length,)` or `(frame_length,)`.\n */\nexport function window_function(\n  window_length: number,\n  name: string,\n  { periodic = true, frame_length = null, center = true } = {},\n) {\n  const length = periodic ? window_length + 1 : window_length;\n  let window;\n  switch (name) {\n    case 'boxcar':\n      window = new Float64Array(length).fill(1.0);\n      break;\n    case 'hann':\n    case 'hann_window':\n      window = hanning(length);\n      break;\n    case 'hamming':\n      window = hamming(length);\n      break;\n    case 'povey':\n      window = hanning(length).map((x) => Math.pow(x, 0.85));\n      break;\n    default:\n      throw new Error(`Unknown window type ${name}.`);\n  }\n  if (periodic) {\n    window = window.subarray(0, window_length);\n  }\n  if (frame_length === null) {\n    return window;\n  }\n  if (window_length > frame_length) {\n    throw new Error(`Length of the window (${window_length}) may not be larger than frame_length (${frame_length})`);\n  }\n\n  return window;\n}\n\n/**\n * Encode audio data to a WAV file.\n * WAV file specs : https://en.wikipedia.org/wiki/WAV#WAV_File_header\n * \n * Adapted from https://www.npmjs.com/package/audiobuffer-to-wav\n * @param {Float32Array} samples The audio samples.\n * @param {number} rate The sample rate.\n * @returns {ArrayBuffer} The WAV audio buffer.\n */\nfunction encodeWAV(samples: Float32Array, rate: number) {\n  let offset = 44;\n  const buffer = new ArrayBuffer(offset + samples.length * 4);\n  const view = new DataView(buffer);\n\n  /* RIFF identifier */\n  writeString(view, 0, \"RIFF\");\n  /* RIFF chunk length */\n  view.setUint32(4, 36 + samples.length * 4, true);\n  /* RIFF type */\n  writeString(view, 8, \"WAVE\");\n  /* format chunk identifier */\n  writeString(view, 12, \"fmt \");\n  /* format chunk length */\n  view.setUint32(16, 16, true);\n  /* sample format (raw) */\n  view.setUint16(20, 3, true);\n  /* channel count */\n  view.setUint16(22, 1, true);\n  /* sample rate */\n  view.setUint32(24, rate, true);\n  /* byte rate (sample rate * block align) */\n  view.setUint32(28, rate * 4, true);\n  /* block align (channel count * bytes per sample) */\n  view.setUint16(32, 4, true);\n  /* bits per sample */\n  view.setUint16(34, 32, true);\n  /* data chunk identifier */\n  writeString(view, 36, \"data\");\n  /* data chunk length */\n  view.setUint32(40, samples.length * 4, true);\n\n  for (let i = 0; i < samples.length; ++i, offset += 4) {\n      view.setFloat32(offset, samples[i], true);\n  }\n\n  return buffer;\n}\n\nfunction writeString(view: DataView, offset: number, string: string) {\n  for (let i = 0; i < string.length; ++i) {\n      view.setUint8(offset + i, string.charCodeAt(i));\n  }\n}\n\n\nexport class RawAudio {\n\n  /**\n   * Create a new `RawAudio` object.\n   * @param {Float32Array} audio Audio data\n   * @param {number} sampling_rate Sampling rate of the audio data\n   */\n  audio: Float32Array;\n  sampling_rate: number;\n\n  constructor(audio: Float32Array, sampling_rate: number) {\n      this.audio = audio\n      this.sampling_rate = sampling_rate\n  }\n\n  /**\n   * Convert the audio to a wav file buffer.\n   * @returns {ArrayBuffer} The WAV file.\n   */\n  toWav() {\n      return encodeWAV(this.audio, this.sampling_rate)\n  }\n\n  /**\n   * Convert the audio to a blob.\n   * @returns {Blob}\n   */\n  toBlob() {\n      const wav = this.toWav();\n      const blob = new Blob([wav], { type: 'audio/wav' });\n      return blob;\n  }\n\n  toArray() {\n    return this.audio;\n  }\n\n  /**\n   * Save the audio to a wav file.\n   * @param {string} path\n   */\n  async save(path: string) {\n      let fn;\n\n      if (apis.IS_BROWSER_ENV) {\n          if (apis.IS_WEBWORKER_ENV) {\n              throw new Error('Unable to save a file from a Web Worker.')\n          }\n          fn = saveBlob;\n      } else if (apis.IS_FS_AVAILABLE) {\n         throw new Error('Unable to save because filesystem is disabled in this environment.')\n      } else {\n          throw new Error('Unable to save because filesystem is disabled in this environment.')\n      }\n\n      await fn(path, this.toBlob())\n  }\n} ","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils';\nimport { Tensor } from '../../utils/tensor';\nimport { mel_filter_bank, spectrogram, window_function } from '../../utils/audio';\n\nexport class ASTFeatureExtractor extends FeatureExtractor {\n  mel_filters: any;\n  window: any;\n  mean: any;\n  std: any;\n\n  constructor(config: any) {\n    super(config);\n\n    const sampling_rate = this.config.sampling_rate;\n    const mel_filters = mel_filter_bank(\n      256, // num_frequency_bins\n      this.config.num_mel_bins, // num_mel_filters\n      20, // min_frequency\n      Math.floor(sampling_rate / 2), // max_frequency\n      sampling_rate, // sampling_rate\n      null, // norm\n      'kaldi', // mel_scale\n      true, // triangularize_in_mel_space\n    );\n\n    // Do padding:\n    for (let i = 0; i < mel_filters.length; ++i) {\n      mel_filters[i].push(0);\n    }\n    this.mel_filters = mel_filters;\n\n    this.window = window_function(400, 'hann', {\n      periodic: false,\n    });\n\n    this.mean = this.config.mean;\n    this.std = this.config.std;\n  }\n\n  /**\n   * Computes the log-Mel spectrogram of the provided audio waveform.\n   * @param {Float32Array|Float64Array} waveform The audio waveform to process.\n   * @param {number} max_length The maximum number of frames to return.\n   * @returns {Promise<Tensor>} An object containing the log-Mel spectrogram data as a Float32Array and its dimensions as an array of numbers.\n   */\n  async _extract_fbank_features(waveform: Float32Array | Float64Array, max_length: number) {\n    // NOTE: We don't pad/truncate since that is passed in as `max_num_frames`\n    return spectrogram(\n      waveform,\n      this.window, // window\n      400, // frame_length\n      160, // hop_length\n      {\n        fft_length: 512,\n        power: 2.0,\n        center: false,\n        preemphasis: 0.97,\n        mel_filters: this.mel_filters,\n        log_mel: 'log',\n        mel_floor: 1.192092955078125e-7,\n        remove_dc_offset: true,\n\n        // Custom\n        max_num_frames: max_length,\n        transpose: true,\n      },\n    );\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_values: Tensor }>} A Promise resolving to an object containing the extracted input features as a Tensor.\n   */\n  async _call(audio: Float32Array | Float64Array) {\n    validate_audio_inputs(audio, 'ASTFeatureExtractor');\n\n    const features = await this._extract_fbank_features(audio, this.config.max_length);\n    if (this.config.do_normalize) {\n      // Normalize the input audio spectrogram to have mean=0, std=0.5\n      const denom = this.std * 2;\n      const features_data = features.data;\n      for (let i = 0; i < features_data.length; ++i) {\n        features_data[i] = (features_data[i] - this.mean) / denom;\n      }\n    }\n\n    return {\n      input_values: features.unsqueeze_(0),\n    };\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\nimport { mel_filter_bank, spectrogram, window_function } from '../../utils/audio.js';\n\nexport class ClapFeatureExtractor extends FeatureExtractor {\n  mel_filters: any;\n  mel_filters_slaney: any;\n  window: any;\n\n  constructor(config: any) {\n    super(config);\n\n    this.mel_filters = mel_filter_bank(\n      this.config.nb_frequency_bins, // num_frequency_bins\n      this.config.feature_size, // num_mel_filters\n      this.config.frequency_min, // min_frequency\n      this.config.frequency_max, // max_frequency\n      this.config.sampling_rate, // sampling_rate\n      null, // norm\n      'htk', // mel_scale\n    );\n\n    this.mel_filters_slaney = mel_filter_bank(\n      this.config.nb_frequency_bins, // num_frequency_bins\n      this.config.feature_size, // num_mel_filters\n      this.config.frequency_min, // min_frequency\n      this.config.frequency_max, // max_frequency\n      this.config.sampling_rate, // sampling_rate\n      'slaney', // norm\n      'slaney', // mel_scale\n    );\n\n    this.window = window_function(this.config.fft_window_size, 'hann');\n  }\n\n  /**\n   * Extracts the mel spectrogram and prepares it for the mode based on the `truncation` and `padding` arguments.\n   *\n   * Four different path are possible:\n   *   - `truncation=\"fusion\"` and the length of the waveform is greater than the max length: the mel spectrogram\n   *     will be computed on the entire audio. 3 random crops and a dowsampled version of the full mel spectrogram\n   *     are then stacked together. They will later be used for `feature_fusion`.\n   *   - `truncation=\"rand_trunc\"` and the length of the waveform is smaller than the max length: the audio is\n   *     padded based on `padding`.\n   *   - `truncation=\"fusion\"` and the length of the waveform is smaller than the max length: the audio is padded\n   *     based on `padding`, and is repeated `4` times.\n   *   - `truncation=\"rand_trunc\"` and the length of the waveform is greater than the max length: the mel\n   *     spectrogram will be computed on a random crop of the waveform.\n   *\n   * @param {Float32Array|Float64Array} waveform The input waveform.\n   * @param {number} max_length The maximum length of the waveform.\n   * @param {string} truncation The truncation strategy to use.\n   * @param {string} padding The padding strategy to use.\n   * @returns {Promise<Tensor>} An object containing the mel spectrogram data as a Float32Array, its dimensions as an array of numbers, and a boolean indicating whether the waveform was longer than the max length.\n   * @private\n   */\n  async _get_input_mel(waveform: Float32Array | Float64Array, max_length: number, truncation: string, padding: string) {\n    /** @type {Tensor} */\n    let input_mel;\n    let longer = false;\n    const diff = waveform.length - max_length;\n    if (diff > 0) {\n      if (truncation === 'rand_trunc') {\n        longer = true;\n        const idx = Math.floor(Math.random() * (diff + 1));\n        waveform = waveform.subarray(idx, idx + max_length);\n\n        input_mel = await this._extract_fbank_features(waveform, this.mel_filters_slaney, this.config.nb_max_samples);\n      } else {\n        // TODO implement fusion strategy\n        throw new Error(`Truncation strategy \"${truncation}\" not implemented`);\n      }\n    } else {\n      if (diff < 0) {\n        let padded = new Float64Array(max_length); // already padded with zeros\n        padded.set(waveform);\n\n        if (padding === 'repeat') {\n          for (let i = waveform.length; i < max_length; i += waveform.length) {\n            padded.set(waveform.subarray(0, Math.min(waveform.length, max_length - i)), i);\n          }\n        } else if (padding === 'repeatpad') {\n          for (let i = waveform.length; i < -diff; i += waveform.length) {\n            padded.set(waveform, i);\n          }\n        }\n        waveform = padded;\n      }\n\n      if (truncation === 'fusion') {\n        throw new Error(`Truncation strategy \"${truncation}\" not implemented`);\n      }\n\n      input_mel = await this._extract_fbank_features(waveform, this.mel_filters_slaney, this.config.nb_max_samples);\n    }\n\n    return input_mel.unsqueeze_(0);\n  }\n\n  /**\n   * Compute the log-mel spectrogram of the provided `waveform` using the Hann window.\n   * In CLAP, two different filter banks are used depending on the truncation pattern:\n   *  - `self.mel_filters`: they correspond to the default parameters of `torchaudio` which can be obtained from\n   *    calling `torchaudio.transforms.MelSpectrogram().mel_scale.fb`. These filters are used when `truncation`\n   *    is set to `\"fusion\"`.\n   *  - `self.mel_filteres_slaney` : they correspond to the default parameters of `librosa` which used\n   *    `librosa.filters.mel` when computing the mel spectrogram. These filters were only used in the original\n   *    implementation when the truncation mode is not `\"fusion\"`.\n   *\n   * @param {Float32Array|Float64Array} waveform The audio waveform to process.\n   * @param {number[][]} mel_filters The mel filters to use.\n   * @param {number} [max_length=null] The maximum number of frames to return.\n   * @returns {Promise<Tensor>} An object containing the log-Mel spectrogram data as a Float32Array and its dimensions as an array of numbers.\n   */\n  async _extract_fbank_features(waveform: Float32Array | Float64Array, mel_filters: any, max_length = null) {\n    // NOTE: We don't pad/truncate since that is passed in as `max_num_frames`\n    return spectrogram(\n      waveform,\n      this.window, // window\n      this.config.fft_window_size, // frame_length\n      this.config.hop_length, // hop_length\n      {\n        power: 2.0,\n        mel_filters,\n        log_mel: 'dB',\n\n        // Custom\n        max_num_frames: max_length,\n        do_pad: false,\n        transpose: true,\n      },\n    );\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_features: Tensor }>} A Promise resolving to an object containing the extracted input features as a Tensor.\n   */\n  async _call(audio: Float32Array | Float64Array, { max_length = null } = {}) {\n    validate_audio_inputs(audio, 'ClapFeatureExtractor');\n\n    // convert to mel spectrogram, truncate and pad if needed.\n    const padded_inputs = await this._get_input_mel(\n      audio,\n      max_length ?? this.config.nb_max_samples,\n      this.config.truncation,\n      this.config.padding,\n    );\n\n    return {\n      input_features: padded_inputs.unsqueeze_(0),\n    };\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\n\nexport class MoonshineFeatureExtractor extends FeatureExtractor {\n  /**\n   * Asynchronously extracts input values from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_values: Tensor; }>} The extracted input values.\n   */\n  async _call(audio) {\n    validate_audio_inputs(audio, 'MoonshineFeatureExtractor');\n\n    if (audio instanceof Float64Array) {\n      audio = new Float32Array(audio);\n    }\n\n    const shape = [1 /* batch_size */, audio.length /* num_samples */];\n    return {\n      input_values: new Tensor('float32', audio, shape),\n    };\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\nimport { max, softmax } from '../../utils/maths.js';\n\nexport class PyAnnoteFeatureExtractor extends FeatureExtractor {\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_values: Tensor; }>} The extracted input features.\n   */\n  async _call(audio) {\n    validate_audio_inputs(audio, 'PyAnnoteFeatureExtractor');\n\n    if (audio instanceof Float64Array) {\n      audio = new Float32Array(audio);\n    }\n\n    const shape = [1 /* batch_size */, 1 /* num_channels */, audio.length /* num_samples */];\n    return {\n      input_values: new Tensor('float32', audio, shape),\n    };\n  }\n\n  /**\n   * NOTE: Can return fractional values. `Math.ceil` will ensure correct value.\n   * @param {number} samples The number of frames in the audio.\n   * @returns {number} The number of frames in the audio.\n   */\n  samples_to_frames(samples) {\n    return (samples - this.config.offset) / this.config.step;\n  }\n\n  /**\n   * Post-processes the speaker diarization logits output by the model.\n   * @param {import('../../utils/tensor.js').Tensor} logits The speaker diarization logits output by the model.\n   * @param {number} num_samples Number of samples in the input audio.\n   * @returns {Array<Array<{ id: number, start: number, end: number, confidence: number }>>} The post-processed speaker diarization results.\n   */\n  post_process_speaker_diarization(logits, num_samples) {\n    const ratio = num_samples / this.samples_to_frames(num_samples) / this.config.sampling_rate;\n\n    const results = [];\n    for (const scores of logits.tolist()) {\n      const accumulated_segments = [];\n\n      let current_speaker = -1;\n      for (let i = 0; i < scores.length; ++i) {\n        /** @type {number[]} */\n        const probabilities = softmax(scores[i]);\n        const [score, id] = max(probabilities);\n        const [start, end] = [i, i + 1];\n\n        if (id !== current_speaker) {\n          // Speaker has changed\n          current_speaker = id;\n          accumulated_segments.push({ id, start, end, score });\n        } else {\n          // Continue the current segment\n          accumulated_segments.at(-1).end = end;\n          accumulated_segments.at(-1).score += score;\n        }\n      }\n\n      results.push(\n        accumulated_segments.map(\n          // Convert frame-space to time-space\n          // and compute the confidence\n          ({ id, start, end, score }) => ({\n            id,\n            start: start * ratio,\n            end: end * ratio,\n            confidence: score / (end - start),\n          }),\n        ),\n      );\n    }\n    return results;\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\nimport { mel_filter_bank, spectrogram, window_function } from '../../utils/audio.js';\n\nexport class SeamlessM4TFeatureExtractor extends FeatureExtractor {\n  constructor(config) {\n    super(config);\n\n    const sampling_rate = this.config.sampling_rate;\n    const mel_filters = mel_filter_bank(\n      256, // num_frequency_bins\n      this.config.num_mel_bins, // num_mel_filters\n      20, // min_frequency\n      Math.floor(sampling_rate / 2), // max_frequency\n      sampling_rate, // sampling_rate\n      null, // norm\n      'kaldi', // mel_scale\n      true, // triangularize_in_mel_space\n    );\n\n    // Do padding:\n    for (let i = 0; i < mel_filters.length; ++i) {\n      mel_filters[i].push(0);\n    }\n    this.mel_filters = mel_filters;\n\n    this.window = window_function(400, 'povey', {\n      periodic: false,\n    });\n  }\n\n  /**\n   * Computes the log-Mel spectrogram of the provided audio waveform.\n   * @param {Float32Array|Float64Array} waveform The audio waveform to process.\n   * @param {number} max_length The maximum number of frames to return.\n   * @returns {Promise<Tensor>} An object containing the log-Mel spectrogram data as a Float32Array and its dimensions as an array of numbers.\n   */\n  async _extract_fbank_features(waveform, max_length) {\n    // NOTE: We don't pad/truncate since that is passed in as `max_num_frames`\n\n    // Kaldi compliance: 16-bit signed integers\n    // 32768 == 2 ** 15\n    waveform = waveform.map((/** @type {number} */ x) => x * 32768);\n\n    return spectrogram(\n      waveform,\n      this.window, // window\n      400, // frame_length\n      160, // hop_length\n      {\n        fft_length: 512,\n        power: 2.0,\n        center: false,\n        preemphasis: 0.97,\n        mel_filters: this.mel_filters,\n        log_mel: 'log',\n        mel_floor: 1.192092955078125e-7,\n        remove_dc_offset: true,\n\n        // Custom\n        max_num_frames: max_length,\n        transpose: true,\n      },\n    );\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @param {Object} options Optional parameters for feature extraction.\n   * @param {boolean} [options.padding=true] Whether to pad the sequence to a multiple of `pad_to_multiple_of`.\n   * @param {number} [options.pad_to_multiple_of=2] The number to pad the sequence to a multiple of.\n   * @param {boolean} [options.do_normalize_per_mel_bins=true] Whether or not to zero-mean unit-variance normalize the input per mel-channel.\n   * @param {boolean} [options.return_attention_mask=true] Whether to return the attention mask.\n   * @returns {Promise<{ input_features: Tensor, attention_mask?: Tensor }>} A Promise resolving to an object containing the extracted input features and attention masks as Tensors.\n   */\n  async _call(\n    audio,\n    { padding = true, pad_to_multiple_of = 2, do_normalize_per_mel_bins = true, return_attention_mask = true } = {},\n  ) {\n    validate_audio_inputs(audio, 'SeamlessM4TFeatureExtractor');\n\n    let features = await this._extract_fbank_features(audio, this.config.max_length);\n\n    if (do_normalize_per_mel_bins) {\n      const [num_features, feature_size] = features.dims;\n      const data = features.data;\n      for (let i = 0; i < feature_size; ++i) {\n        let sum = 0;\n        for (let j = 0; j < num_features; ++j) {\n          sum += data[j * feature_size + i];\n        }\n\n        const mean = sum / num_features;\n\n        let variance = 0;\n        for (let j = 0; j < num_features; ++j) {\n          variance += (data[j * feature_size + i] - mean) ** 2;\n        }\n        variance /= num_features - 1; // NOTE: We use ddof=1\n\n        const std = Math.sqrt(variance + 1e-7);\n        for (let j = 0; j < num_features; ++j) {\n          const index = j * feature_size + i;\n          data[index] = (data[index] - mean) / std;\n        }\n      }\n    }\n\n    let padded_attention_mask;\n    if (padding) {\n      const [num_frames, num_channels] = features.dims;\n      const data = /** @type {Float32Array} */ features.data;\n\n      const pad_size = num_frames % pad_to_multiple_of;\n      if (pad_size > 0) {\n        const padded_data = new Float32Array(num_channels * (num_frames + pad_size));\n        padded_data.set(data);\n        padded_data.fill(this.config.padding_value, data.length);\n\n        const numPaddedFrames = num_frames + pad_size;\n        features = new Tensor(features.type, padded_data, [numPaddedFrames, num_channels]);\n\n        if (return_attention_mask) {\n          padded_attention_mask = new Tensor('int64', new BigInt64Array(numPaddedFrames), [1, numPaddedFrames]);\n          /** @type {BigInt64Array} */ padded_attention_mask.data.fill(1n, 0, num_frames);\n        }\n      }\n    }\n\n    const [num_frames, num_channels] = features.dims;\n\n    const stride = this.config.stride;\n    const remainder = num_frames % stride;\n    if (remainder !== 0) {\n      throw new Error(`The number of frames (${num_frames}) must be a multiple of the stride (${stride}).`);\n    }\n\n    const input_features = features.view(1, Math.floor(num_frames / stride), num_channels * stride);\n\n    const result = { input_features };\n\n    if (return_attention_mask) {\n      const reshapedNumFrames = input_features.dims[1];\n\n      const attention_mask_data = new BigInt64Array(reshapedNumFrames);\n\n      if (padded_attention_mask) {\n        const padded_attention_mask_data = padded_attention_mask.data;\n        for (let i = 1, j = 0; i < num_frames; i += stride, ++j) {\n          attention_mask_data[j] = padded_attention_mask_data[i];\n        }\n      } else {\n        attention_mask_data.fill(1n);\n      }\n      result.attention_mask = new Tensor('int64', attention_mask_data, [1, reshapedNumFrames]);\n    }\n\n    return result;\n  }\n}\n","import { FeatureExtractor } from '../../base/feature_extraction_utils.js';\n\nexport class SpeechT5FeatureExtractor extends FeatureExtractor {}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\n\nexport class Wav2Vec2FeatureExtractor extends FeatureExtractor {\n  /**\n   * @param {Float32Array} input_values\n   * @returns {Float32Array}\n   */\n  _zero_mean_unit_var_norm(input_values) {\n    // TODO support batch?\n    const sum = input_values.reduce((a, b) => a + b, 0);\n    const mean = sum / input_values.length;\n    const variance = input_values.reduce((a, b) => a + (b - mean) ** 2, 0) / input_values.length;\n    return input_values.map((x) => (x - mean) / Math.sqrt(variance + 1e-7));\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_values: Tensor; attention_mask: Tensor }>} A Promise resolving to an object containing the extracted input features and attention mask as Tensors.\n   */\n  async _call(audio) {\n    validate_audio_inputs(audio, 'Wav2Vec2FeatureExtractor');\n\n    if (audio instanceof Float64Array) {\n      audio = new Float32Array(audio);\n    }\n\n    let input_values = audio;\n\n    // zero-mean and unit-variance normalization\n    if (this.config.do_normalize) {\n      input_values = this._zero_mean_unit_var_norm(input_values);\n    }\n\n    // TODO: allow user to pass in attention mask\n    const shape = [1, input_values.length];\n    return {\n      input_values: new Tensor('float32', input_values, shape),\n      attention_mask: new Tensor('int64', new BigInt64Array(input_values.length).fill(1n), shape),\n    };\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils.js';\nimport { Tensor } from '../../utils/tensor.js';\nimport { mel_filter_bank, spectrogram, window_function } from '../../utils/audio.js';\n\nexport class WeSpeakerFeatureExtractor extends FeatureExtractor {\n  constructor(config) {\n    super(config);\n\n    const sampling_rate = this.config.sampling_rate;\n    const mel_filters = mel_filter_bank(\n      256, // num_frequency_bins\n      this.config.num_mel_bins, // num_mel_filters\n      20, // min_frequency\n      Math.floor(sampling_rate / 2), // max_frequency\n      sampling_rate, // sampling_rate\n      null, // norm\n      'kaldi', // mel_scale\n      true, // triangularize_in_mel_space\n    );\n\n    // Do padding:\n    for (let i = 0; i < mel_filters.length; ++i) {\n      mel_filters[i].push(0);\n    }\n    this.mel_filters = mel_filters;\n\n    this.window = window_function(400, 'hamming', {\n      periodic: false,\n    });\n    this.min_num_frames = this.config.min_num_frames;\n  }\n\n  /**\n   * Computes the log-Mel spectrogram of the provided audio waveform.\n   * @param {Float32Array|Float64Array} waveform The audio waveform to process.\n   * @returns {Promise<Tensor>} An object containing the log-Mel spectrogram data as a Float32Array and its dimensions as an array of numbers.\n   */\n  async _extract_fbank_features(waveform) {\n    // Kaldi compliance: 16-bit signed integers\n    // 32768 == 2 ** 15\n    waveform = waveform.map((/** @type {number} */ x) => x * 32768);\n\n    return spectrogram(\n      waveform,\n      this.window, // window\n      400, // frame_length\n      160, // hop_length\n      {\n        fft_length: 512,\n        power: 2.0,\n        center: false,\n        preemphasis: 0.97,\n        mel_filters: this.mel_filters,\n        log_mel: 'log',\n        mel_floor: 1.192092955078125e-7,\n        remove_dc_offset: true,\n\n        // Custom\n        transpose: true,\n        min_num_frames: this.min_num_frames,\n      },\n    );\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_features: Tensor }>} A Promise resolving to an object containing the extracted input features as a Tensor.\n   */\n  async _call(audio) {\n    validate_audio_inputs(audio, 'WeSpeakerFeatureExtractor');\n\n    const features = (await this._extract_fbank_features(audio)).unsqueeze_(0);\n\n    if (this.config.fbank_centering_span === null) {\n      // center features with global average\n      const meanData = /** @type {Float32Array} */ features.mean(1).data;\n      const featuresData = /** @type {Float32Array} */ features.data;\n      const [batch_size, num_frames, feature_size] = features.dims;\n\n      for (let i = 0; i < batch_size; ++i) {\n        const offset1 = i * num_frames * feature_size;\n        const offset2 = i * feature_size;\n        for (let j = 0; j < num_frames; ++j) {\n          const offset3 = offset1 + j * feature_size;\n          for (let k = 0; k < feature_size; ++k) {\n            featuresData[offset3 + k] -= meanData[offset2 + k];\n          }\n        }\n      }\n    }\n\n    return {\n      input_features: features,\n    };\n  }\n}\n","import { FeatureExtractor, validate_audio_inputs } from '../../base/feature_extraction_utils';\nimport { Tensor } from '../../utils/tensor';\nimport { mel_filter_bank, spectrogram, window_function } from '../../utils/audio';\nimport { max } from '../../utils/maths';\nimport { AutomaticSpeechRecognitionConfig } from '../../pipelines';\nexport class WhisperFeatureExtractor extends FeatureExtractor {\n  constructor(config: Partial<AutomaticSpeechRecognitionConfig>) {\n    super(config);\n\n    // Prefer given `mel_filters` from preprocessor_configon, or calculate them if they don't exist.\n    this.config.mel_filters ??= mel_filter_bank(\n      Math.floor(1 + this.config.n_fft / 2), // num_frequency_bins\n      this.config.feature_size, // num_mel_filters\n      0.0, // min_frequency\n      8000.0, // max_frequency\n      this.config.sampling_rate, // sampling_rate\n      'slaney', // norm\n      'slaney', // mel_scale\n    );\n\n    this.window = window_function(this.config.n_fft, 'hann');\n  }\n\n  /**\n   * Computes the log-Mel spectrogram of the provided audio waveform.\n   * @param {Float32Array|Float64Array} waveform The audio waveform to process.\n   * @returns {Promise<Tensor>} An object containing the log-Mel spectrogram data as a Float32Array and its dimensions as an array of numbers.\n   */\n  async _extract_fbank_features(waveform: Float32Array | Float64Array) {\n    const features = await spectrogram(\n      waveform,\n      this.window, // window\n      this.config.n_fft, // frame_length\n      this.config.hop_length, // hop_length\n      {\n        power: 2.0,\n        mel_filters: this.config.mel_filters,\n        log_mel: 'log10',\n\n        // Custom\n        max_num_frames: this.config.nb_max_frames, // 3000\n      },\n    );\n\n    const data = features.data;\n    const maxValue = max(/** @type {Float32Array} */ data)[0];\n\n    for (let i = 0; i < data.length; ++i) {\n      data[i] = (Math.max(data[i], maxValue - 8.0) + 4.0) / 4.0;\n    }\n\n    return features;\n  }\n\n  /**\n   * Asynchronously extracts features from a given audio using the provided configuration.\n   * @param {Float32Array|Float64Array} audio The audio data as a Float32Array/Float64Array.\n   * @returns {Promise<{ input_features: Tensor }>} A Promise resolving to an object containing the extracted input features as a Tensor.\n   */\n  async _call(audio: AudioPipelineInputs) {\n    validate_audio_inputs(audio, 'WhisperFeatureExtractor');\n\n    let waveform;\n    if (audio.length > this.config.n_samples) {\n      console.warn(\n        'Attempting to extract features for audio longer than 30 seconds. ' +\n          'If using a pipeline to extract transcript from a long audio clip, ' +\n          'remember to specify `chunk_length_s` and/or `stride_length_s`.',\n      );\n      waveform = audio.slice(0, this.config.n_samples);\n    } else {\n      // pad with zeros\n      waveform = new Float32Array(this.config.n_samples);\n      waveform.set(audio);\n    }\n\n    const features = await this._extract_fbank_features(waveform);\n\n    return {\n      input_features: features.unsqueeze_(0),\n    };\n  }\n}\n","import { FEATURE_EXTRACTOR_NAME, GITHUB_ISSUE_URL } from '../../utils/constants.js';\nimport { getModelJSON } from '../../utils/hub.js';\nimport { FeatureExtractor } from '../../base/feature_extraction_utils.js';\nimport * as AllFeatureExtractors from '../feature_extractors.js';\n\nexport class AutoFeatureExtractor {\n  /** @type {typeof FeatureExtractor.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options = {}) {\n    const preprocessorConfig = await getModelJSON(pretrained_model_name_or_path, FEATURE_EXTRACTOR_NAME, true, options);\n\n    // Determine feature extractor class\n    const key = preprocessorConfig.feature_extractor_type;\n    const feature_extractor_class = AllFeatureExtractors[key as keyof typeof AllFeatureExtractors];\n\n    if (!feature_extractor_class) {\n      throw new Error(`Unknown feature_extractor_type: '${key}'. Please report this at ${GITHUB_ISSUE_URL}.`);\n    }\n\n    // Instantiate feature extractor\n    return new feature_extractor_class(preprocessorConfig);\n  }\n}\n","import { AutoFeatureExtractor } from '../auto/feature_extraction_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { Processor } from '../../base/processing_utils.js';\n\n/**\n * Represents a MoonshineProcessor that extracts features from an audio input.\n */\nexport class MoonshineProcessor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static feature_extractor_class = AutoFeatureExtractor;\n\n  /**\n   * Calls the feature_extractor function with the given audio input.\n   * @param {any} audio The audio input to extract features from.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(audio) {\n    return await this.feature_extractor(audio);\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { mergeArrays } from '../../utils/core.js';\nimport { Tensor } from '../../utils/tensor.js';\nimport { RawImage } from '../../utils/image.js';\n\nexport class VLChatProcessor extends Processor {\n  static image_processor_class = AutoImageProcessor;\n  static tokenizer_class = AutoTokenizer;\n  static uses_processor_config = true;\n\n  constructor(config, components) {\n    super(config, components);\n\n    this.image_tag = this.config.image_tag;\n    this.image_start_tag = this.config.image_start_tag;\n    this.image_end_tag = this.config.image_end_tag;\n    this.num_image_tokens = this.config.num_image_tokens;\n  }\n\n  /**\n   * @typedef {Object} MultimodalMessageProperties Additional properties for multimodal messages.\n   * @property {(RawImage | string | URL)[]} [images] The images in the message.\n   * @typedef {(import('../../tokenizers.js').Message & MultimodalMessageProperties)[]} MultimodalConversation The conversation possibly containing multimodal inputs.\n   */\n\n  /**\n   * @typedef {Object} VLCChatProcessorResult The processed input.\n   * @property {Tensor} input_ids The input IDs.\n   * @property {Tensor} attention_mask The attention mask.\n   * @property {Tensor} images_seq_mask The image sequence mask.\n   * @property {Tensor} images_emb_mask The image embedding mask.\n   */\n\n  /**\n   * @param {MultimodalConversation} conversation The chat messages to process.\n   * @param {Object} options Additional options for processing.\n   * @param {RawImage|RawImage[]} [options.images] The images to process, if not set in the conversation.\n   * @param {string} [options.chat_template=\"default\"] The chat template to use.\n   * @returns {Promise<VLCChatProcessorResult | VLCChatProcessorResult & import('../../base/image_processors_utils.js').ImageProcessorResult>} The processed input.\n   */\n  async _call(conversation, { images = null, chat_template = 'default' } = {}) {\n    if (!images) {\n      images = await Promise.all(\n        conversation\n          .filter((msg) => msg.images)\n          .flatMap((msg) => msg.images)\n          .map((img) => RawImage.read(img)),\n      );\n    } else if (!Array.isArray(images)) {\n      images = [images];\n    }\n\n    const tokenizer = this.tokenizer;\n    const result = tokenizer.apply_chat_template(conversation, {\n      tokenize: false,\n      add_generation_prompt: true,\n      chat_template,\n    });\n\n    const encode = (text) => tokenizer.encode(text, { add_special_tokens: false });\n    const parts = /** @type {string} */ result.split(this.image_tag);\n    const num_images = parts.length - 1;\n    if (images.length !== num_images) {\n      throw new Error(\n        `Number of images provided (${images.length}) does not match number of \"${this.image_tag}\" image tags (${num_images})`,\n      );\n    }\n\n    const [image_placeholder_tag_id, image_start_tag_id, image_end_tag_id] = tokenizer.model.convert_tokens_to_ids([\n      this.image_tag,\n      this.image_start_tag,\n      this.image_end_tag,\n    ]);\n\n    let input_ids = encode(parts[0]);\n    let images_seq_mask = new Array(input_ids.length).fill(false);\n    for (let i = 1; i < parts.length; ++i) {\n      const placeholder_image_tokens = new Array(this.num_image_tokens).fill(image_placeholder_tag_id);\n      const tokens = encode(parts[i]);\n      input_ids = mergeArrays(input_ids, [image_start_tag_id], placeholder_image_tokens, [image_end_tag_id], tokens);\n      const image_mask = new Array(this.num_image_tokens).fill(true);\n      images_seq_mask = mergeArrays(\n        images_seq_mask,\n        [false],\n        image_mask,\n        [false],\n        new Array(tokens.length).fill(false),\n      );\n    }\n\n    const dims = [1, input_ids.length];\n    const final = {\n      input_ids: new Tensor('int64', input_ids, dims),\n      attention_mask: new Tensor('int64', new Array(input_ids.length).fill(1), dims),\n      images_seq_mask: new Tensor('bool', images_seq_mask, dims),\n      images_emb_mask: new Tensor('bool', new Array(num_images * this.num_image_tokens).fill(true), [\n        1,\n        num_images,\n        this.num_image_tokens,\n      ]),\n    };\n\n    if (images && images.length > 0) {\n      const image_inputs = await this.image_processor(images);\n      // Set the batch_size dimension to 1\n      image_inputs.pixel_values.unsqueeze_(0);\n      return { ...final, ...image_inputs };\n    }\n\n    return final;\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\n\nexport class JinaCLIPProcessor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static image_processor_class = AutoImageProcessor;\n\n  async _call(text = null, images = null, kwargs = {}) {\n    if (!text && !images) {\n      throw new Error('Either text or images must be provided');\n    }\n\n    const text_inputs = text ? this.tokenizer(text, kwargs) : {};\n    const image_inputs = images ? await this.image_processor(images, kwargs) : {};\n\n    return {\n      ...text_inputs,\n      ...image_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { RawImage } from '../../utils/image.js';\n\nconst IMAGE_TOKEN = '<|image|>';\nconst IMAGE_TOKEN_PATTERN = /<\\|image_\\d+\\|>/g;\n\nexport class Phi3VProcessor extends Processor {\n  static image_processor_class = AutoImageProcessor;\n  static tokenizer_class = AutoTokenizer;\n\n  /**\n   *\n   * @param {string|string[]} text\n   * @param {RawImage|RawImage[]} images\n   * @param  { { padding?: boolean, truncation?: boolean, num_crops?: number } | undefined } options\n   * @returns {Promise<any>}\n   */\n  async _call(text, images = null, { padding = true, truncation = true, num_crops = null } = {}) {\n    if (!Array.isArray(text)) {\n      text = [text];\n    }\n\n    let text_inputs, image_inputs;\n    if (images) {\n      image_inputs = await this.image_processor(images, { num_crops });\n      const { num_img_tokens } = image_inputs;\n\n      // The original implementation adds a bos_token before the image tokens\n      // TODO: Check if this affects performance, since it looks like a bug in the original implementation\n      const prompt_chunks = text.map((t, i) =>\n        t.split(IMAGE_TOKEN_PATTERN).join(IMAGE_TOKEN.repeat(num_img_tokens[i])),\n      );\n\n      text_inputs = this.tokenizer(prompt_chunks, { padding, truncation });\n\n      // The model expects image tokens to be negative, so we negate the image token ids\n      const image_token_id = this.tokenizer.model.convert_tokens_to_ids([IMAGE_TOKEN])[0];\n      text_inputs.input_ids.map_((id) => (id == image_token_id ? -id : id));\n    } else {\n      text_inputs = this.tokenizer(text);\n    }\n\n    return {\n      ...text_inputs,\n      ...image_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\n\nconst IMAGE_TOKEN = '<image>';\n\nfunction build_string_from_input(prompt, bos_token, image_seq_len, image_token, num_images) {\n  return `${image_token.repeat(image_seq_len * num_images)}${bos_token}${prompt}\\n`;\n}\n\nexport class PaliGemmaProcessor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static image_processor_class = AutoImageProcessor;\n  static uses_processor_config = false;\n\n  /**\n   * @typedef {import('../../utils/image.js').RawImage} RawImage\n   */\n\n  // `images` is required, `text` is optional\n  async _call(/** @type {RawImage|RawImage[]} */ images, text = null, kwargs = {}) {\n    if (!text) {\n      console.warn('You are using PaliGemma without a text prefix. It will perform as a picture-captioning model.');\n      text = '';\n    }\n\n    if (!Array.isArray(images)) {\n      images = [images];\n    }\n\n    if (!Array.isArray(text)) {\n      text = [text];\n    }\n\n    const bos_token = this.tokenizer.bos_token;\n    // @ts-expect-error TS2339\n    const image_seq_length = this.image_processor.config.image_seq_length;\n    let input_strings;\n    if (text.some((t) => t.includes(IMAGE_TOKEN))) {\n      input_strings = text.map((sample) => {\n        const expanded_sample = sample.replaceAll(IMAGE_TOKEN, IMAGE_TOKEN.repeat(image_seq_length));\n        const bos_rfind_index = expanded_sample.lastIndexOf(IMAGE_TOKEN);\n        const bos_index = bos_rfind_index === -1 ? 0 : bos_rfind_index + IMAGE_TOKEN.length;\n        return expanded_sample.slice(0, bos_index) + bos_token + expanded_sample.slice(bos_index) + '\\n';\n      });\n    } else {\n      console.warn(\n        'You are passing both `text` and `images` to `PaliGemmaProcessor`. The processor expects special ' +\n          'image tokens in the text, as many tokens as there are images per each text. It is recommended to ' +\n          'add `<image>` tokens in the very beginning of your text. For this call, we will infer how many images ' +\n          'each text has and add special tokens.',\n      );\n\n      input_strings = text.map((sample) =>\n        build_string_from_input(sample, bos_token, image_seq_length, IMAGE_TOKEN, images.length),\n      );\n    }\n\n    const text_inputs = this.tokenizer(input_strings, kwargs);\n    const image_inputs = await this.image_processor(images, kwargs);\n\n    return {\n      ...image_inputs,\n      ...text_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { PyAnnoteFeatureExtractor } from './feature_extraction_pyannote.js';\n\nexport class PyAnnoteProcessor extends Processor {\n  static feature_extractor_class = PyAnnoteFeatureExtractor;\n\n  /**\n   * Calls the feature_extractor function with the given audio input.\n   * @param {any} audio The audio input to extract features from.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(audio) {\n    return await this.feature_extractor(audio);\n  }\n\n  /** @type {PyAnnoteFeatureExtractor['post_process_speaker_diarization']} */\n  post_process_speaker_diarization(...args) {\n    return /** @type {PyAnnoteFeatureExtractor} */ this.feature_extractor.post_process_speaker_diarization(...args);\n  }\n\n  get sampling_rate() {\n    return this.feature_extractor.config.sampling_rate;\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { RawImage } from '../../utils/image.js';\n\nexport class Qwen2VLProcessor extends Processor {\n  static image_processor_class = AutoImageProcessor;\n  static tokenizer_class = AutoTokenizer;\n\n  /**\n   *\n   * @param {string|string[]} text\n   * @param {RawImage|RawImage[]} images\n   * @param  {...any} args\n   * @returns {Promise<any>}\n   */\n  async _call(text, images = null, ...args) {\n    if (!Array.isArray(text)) {\n      text = [text];\n    }\n\n    let image_inputs, image_grid_thw;\n\n    if (images) {\n      image_inputs = await this.image_processor(images);\n      image_grid_thw = image_inputs.image_grid_thw;\n    }\n\n    if (image_grid_thw) {\n      // @ts-expect-error TS2551\n      let merge_length = this.image_processor.config.merge_size ** 2;\n      let index = 0;\n\n      const image_grid_thw_list = image_grid_thw.tolist();\n      text = text.map((t) => {\n        while (t.includes('<|image_pad|>')) {\n          const prod = Number(image_grid_thw_list[index++].reduce((a, b) => a * b, 1n));\n          t = t.replace('<|image_pad|>', '<|placeholder|>'.repeat(Math.floor(prod / merge_length)));\n        }\n        return t.replaceAll('<|placeholder|>', '<|image_pad|>');\n      });\n    }\n\n    const text_inputs = this.tokenizer(text);\n\n    return {\n      ...text_inputs,\n      ...image_inputs,\n      // TODO: ...videos_inputs,\n    };\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoImageProcessor } from '../auto/image_processing_auto.js';\n\nexport class SamProcessor extends Processor {\n  static image_processor_class = AutoImageProcessor;\n\n  async _call(...args) {\n    return await this.image_processor(...args);\n  }\n\n  post_process_masks(...args) {\n    // @ts-ignore\n    return this.image_processor.post_process_masks(...args);\n  }\n\n  reshape_input_points(...args) {\n    // @ts-ignore\n    return this.image_processor.reshape_input_points(...args);\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoTokenizer } from '../../tokenizers.js';\nimport { AutoFeatureExtractor } from '../auto/feature_extraction_auto.js';\n\nexport class SpeechT5Processor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static feature_extractor_class = AutoFeatureExtractor;\n\n  /**\n   * Calls the feature_extractor function with the given input.\n   * @param {any} input The input to extract features from.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(input) {\n    return await this.feature_extractor(input);\n  }\n}\n","import { Processor } from '../../base/processing_utils.js';\nimport { AutoFeatureExtractor } from '../auto/feature_extraction_auto.js';\n\nexport class Wav2Vec2ProcessorWithLM extends Processor {\n  static feature_extractor_class = AutoFeatureExtractor;\n\n  /**\n   * Calls the feature_extractor function with the given audio input.\n   * @param {any} audio The audio input to extract features from.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(audio) {\n    return await this.feature_extractor(audio);\n  }\n}\n","import { AutoFeatureExtractor } from '../auto/feature_extraction_auto';\nimport { AutoTokenizer } from '../../tokenizers';\nimport { Processor } from '../../base/processing_utils';\n\n/**\n * Represents a WhisperProcessor that extracts features from an audio input.\n */\nexport class WhisperProcessor extends Processor {\n  static tokenizer_class = AutoTokenizer;\n  static feature_extractor_class = AutoFeatureExtractor;\n\n  /**\n   * Calls the feature_extractor function with the given audio input.\n   * @param {any} audio The audio input to extract features from.\n   * @returns {Promise<any>} A Promise that resolves with the extracted features.\n   */\n  async _call(audio) {\n    return await this.feature_extractor(audio);\n  }\n}\n","export * from './bit/image_processing_bit';\nexport * from './chinese_clip/image_processing_chinese_clip';\nexport * from './clip/image_processing_clip';\nexport * from './convnext/image_processing_convnext';\nexport * from './deit/image_processing_deit';\nexport * from './idefics3/image_processing_idefics3';\nexport * from './janus/image_processing_janus';\nexport * from './jina_clip/image_processing_jina_clip';\nexport * from './llava_onevision/image_processing_llava_onevision';\nexport * from './phi3_v/image_processing_phi3_v';\nexport * from './qwen2_vl/image_processing_qwen2_vl';\nexport * from './sam/image_processing_sam';\nexport * from './siglip/image_processing_siglip';\nexport * from './swin2sr/image_processing_swin2sr';\nexport * from './vitmatte/image_processing_vitmatte';\nexport * from './vitpose/image_processing_vitpose';\n","import { ImageProcessor } from '../../base/image_processors_utils';\n\nexport class BitImageProcessor extends ImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils';\n\nexport class ChineseCLIPFeatureExtractor extends ImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class CLIPImageProcessor extends ImageProcessor {}\nexport class CLIPFeatureExtractor extends CLIPImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class ConvNextImageProcessor extends ImageProcessor {\n  constructor(config: any) {\n    super(config);\n\n    /**\n     * Percentage of the image to crop. Only has an effect if this.size < 384.\n     */\n    // @ts-expect-error TS2339\n    this.crop_pct = this.config.crop_pct ?? 224 / 256;\n  }\n\n  async resize(image: any) {\n    const shortest_edge = this.size?.shortest_edge;\n    if (shortest_edge === undefined) {\n      throw new Error(`Size dictionary must contain 'shortest_edge' key.`);\n    }\n\n    if (shortest_edge < 384) {\n      // maintain same ratio, resizing shortest edge to shortest_edge/crop_pct\n      const resize_shortest_edge = Math.floor(shortest_edge / this.crop_pct);\n\n      const [newWidth, newHeight] = this.get_resize_output_image_size(image, {\n        shortest_edge: resize_shortest_edge,\n      });\n\n      image = await image.resize(newWidth, newHeight, {\n        resample: this.resample,\n      });\n\n      // then crop to (shortest_edge, shortest_edge)\n      image = await image.center_crop(shortest_edge, shortest_edge);\n    } else {\n      // warping (no cropping) when evaluated at 384 or larger\n      image = await image.resize(shortest_edge, shortest_edge, {\n        resample: this.resample,\n      });\n    }\n\n    return image;\n  }\n}\nexport class ConvNextFeatureExtractor extends ConvNextImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class DeiTImageProcessor extends ImageProcessor {}\nexport class DeiTFeatureExtractor extends DeiTImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\nimport { RawImage } from '../../utils/image.js';\nimport { cat, full, interpolate_4d, slice, stack, Tensor } from '../../utils/tensor.js';\n\nexport class Idefics3ImageProcessor extends ImageProcessor {\n  do_image_splitting: boolean;\n  max_image_size: [number, number];\n\n  constructor(config: any) {\n    super(config);\n\n    this.do_image_splitting = config.do_image_splitting ?? true;\n    this.max_image_size = config.max_image_size;\n  }\n\n  /**\n   * @typedef {import('../../utils/image.js').RawImage} RawImage\n   * @typedef {import('../../utils/tensor.js').Tensor} Tensor\n   */\n\n  /**\n   * Calculate size to resize images to, to be multiples of `vision_encoder_max_size` while preserving the aspect ratio.\n   * @param {Tensor} pixel_values Tensor of the image to resize.\n   * @param {number} vision_encoder_max_size Maximum size of the output image. If the image is larger than this size,\n   * it will be split into patches of this size, and the original image will be concatenated with the patches, resized to max_size.\n   */\n  get_resize_for_vision_encoder(pixel_values: Tensor, vision_encoder_max_size: number) {\n    let [height, width] = pixel_values.dims.slice(-2);\n\n    const aspect_ratio = width / height;\n    if (width >= height) {\n      width = Math.ceil(width / vision_encoder_max_size) * vision_encoder_max_size;\n      height = Math.floor(width / aspect_ratio);\n      height = Math.ceil(height / vision_encoder_max_size) * vision_encoder_max_size;\n    } else {\n      height = Math.ceil(height / vision_encoder_max_size) * vision_encoder_max_size;\n      width = Math.floor(height * aspect_ratio);\n      width = Math.ceil(width / vision_encoder_max_size) * vision_encoder_max_size;\n    }\n    return { height, width };\n  }\n\n  /** @param {RawImage|RawImage[]|RawImage[][]} images */\n  async _call(\n    images: RawImage | RawImage[] | RawImage[][],\n    { do_image_splitting = null, return_row_col_info = false } = {},\n  ) {\n    /** @type {RawImage[][]} */\n    let batched_2d_images;\n    if (!Array.isArray(images)) {\n      batched_2d_images = [[images]];\n    } else {\n      if (images.length === 0 || !images[0]) {\n        throw new Error('No images provided.');\n      }\n      if (!Array.isArray(images[0])) {\n        batched_2d_images = [/** @type {RawImage[]} */ images];\n      } else {\n        batched_2d_images = /** @type {RawImage[][]} */ images;\n      }\n    }\n\n    // List of tensors, each with shape [patches, channels, height, width]\n    let all_pixel_values = [];\n    let images_list_rows = [];\n    let images_list_cols = [];\n\n    const original_sizes = [];\n    const reshaped_input_sizes = [];\n    for (const image_batch of batched_2d_images) {\n      let images_list = await Promise.all((image_batch as RawImage[]).map((x) => this.preprocess(x)));\n\n      // Original sizes of images\n      original_sizes.push(...images_list.map((x: any) => x.original_size));\n\n      // Reshaped sizes of images, before padding or cropping\n      reshaped_input_sizes.push(...images_list.map((x: any) => x.reshaped_input_size));\n\n      // Convert images to 4D tensors for easier processing\n      images_list.forEach((x: any) => x.pixel_values.unsqueeze_(0));\n\n      const longest_edge = this.max_image_size[0];\n\n      /** @type {Tensor[]} */\n      let images_tensor;\n      if (do_image_splitting ?? this.do_image_splitting) {\n        let image_rows = new Array(images_list.length);\n        let image_cols = new Array(images_list.length);\n\n        // We first resize both height and width of each image to the nearest max_image_size multiple, disregarding the aspect ratio\n        images_tensor = await Promise.all(\n          images_list.map(async (x: any, i: number) => {\n            const new_size = this.get_resize_for_vision_encoder(x.pixel_values, longest_edge);\n\n            const resized = await interpolate_4d(x.pixel_values, {\n              size: [new_size.height, new_size.width],\n            });\n\n            const { frames, num_splits_h, num_splits_w } = await this.split_image(resized, {\n              longest_edge: this.max_image_size[0],\n            });\n            image_rows[i] = num_splits_h;\n            image_cols[i] = num_splits_w;\n            return cat(frames, 0);\n          }),\n        );\n\n        images_list_rows.push(image_rows);\n        images_list_cols.push(image_cols);\n      } else {\n        /** @type {[number, number]} */\n        const size = [longest_edge, longest_edge];\n        images_tensor = await Promise.all(images_list.map((x: any) => interpolate_4d(x.pixel_values, { size })));\n\n        images_list_rows.push(new Array(images_list.length).fill(0));\n        images_list_cols.push(new Array(images_list.length).fill(0));\n      }\n\n      all_pixel_values.push(cat(images_tensor, 0));\n    }\n\n    const batch_size = all_pixel_values.length;\n    const [n, c, h, w] = all_pixel_values[0].dims;\n\n    // Stack pixel values\n    let pixel_values;\n    let pixel_attention_mask;\n    if (batch_size === 1) {\n      pixel_values = all_pixel_values[0].unsqueeze_(0);\n      pixel_attention_mask = full([batch_size, n, h, w], true);\n    } else {\n      // Add padding (if necessary) to images with less patches than the maximum number of patches\n      const max_num_patches = Math.max(...all_pixel_values.map((x) => x.dims.at(0)));\n\n      pixel_attention_mask = full([batch_size, max_num_patches, h, w], true);\n      const pixel_attention_mask_data = pixel_attention_mask.data as any;\n      const pixel_attention_mask_stride = max_num_patches * h * w;\n      for (let i = 0; i < batch_size; ++i) {\n        const num_patches: number = all_pixel_values[i].dims[0];\n        if (num_patches < max_num_patches) {\n          all_pixel_values[i] = cat([all_pixel_values[i], full([max_num_patches - num_patches, c, h, w], 0)], 0);\n\n          const start_offset = i * pixel_attention_mask_stride + num_patches * h * w;\n          const end_offset = (i + 1) * pixel_attention_mask_stride;\n\n          pixel_attention_mask_data.fill(false, start_offset, end_offset);\n        }\n      }\n      pixel_values = stack(all_pixel_values, 0);\n    }\n\n    return {\n      pixel_values,\n      pixel_attention_mask,\n\n      original_sizes,\n      reshaped_input_sizes,\n      ...(return_row_col_info ? { rows: images_list_rows, cols: images_list_cols } : {}),\n    };\n  }\n\n  async split_image(pixel_values: Tensor, { longest_edge }: { longest_edge: number }) {\n    const max_height = longest_edge;\n    const max_width = longest_edge;\n\n    const frames = [];\n\n    const [height, width] = pixel_values.dims.slice(-2);\n\n    let num_splits_h = 0,\n      num_splits_w = 0;\n\n    if (height > max_height || width > max_width) {\n      // Calculate the number of splits\n      num_splits_h = Math.ceil(height / max_height);\n      num_splits_w = Math.ceil(width / max_width);\n\n      // Calculate the optimal width and height for the sub-images\n      const optimal_height = Math.ceil(height / num_splits_h);\n      const optimal_width = Math.ceil(width / num_splits_w);\n\n      // Iterate through each row and column\n      for (let r = 0; r < num_splits_h; ++r) {\n        for (let c = 0; c < num_splits_w; ++c) {\n          let start_x, start_y, end_x, end_y;\n          if (r === num_splits_h - 1) {\n            // At bottom\n            start_y = height - optimal_height;\n            end_y = height;\n          } else {\n            start_y = r * optimal_height;\n            end_y = (r + 1) * optimal_height;\n          }\n          if (c === num_splits_w - 1) {\n            // At right\n            start_x = width - optimal_width;\n            end_x = width;\n          } else {\n            start_x = c * optimal_width;\n            end_x = (c + 1) * optimal_width;\n          }\n\n          const starts = [start_y, start_x];\n          const ends = [end_y, end_x];\n\n          const patch = await slice(pixel_values, starts, ends, [2, 3]);\n          frames.push(patch);\n        }\n      }\n\n      // Resize the global image to match max dimensions for memory efficiency\n      const global_image_height = max_height;\n      const global_image_width = max_width;\n\n      if (height !== global_image_height || width !== global_image_width) {\n        pixel_values = await interpolate_4d(pixel_values, {\n          size: [global_image_height, global_image_width],\n        });\n      }\n    }\n\n    frames.push(pixel_values);\n\n    return { frames, num_splits_h, num_splits_w };\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class JinaCLIPImageProcessor extends ImageProcessor {\n  constructor(config) {\n    // JinaCLIPImageProcessor uses a custom preprocessor_config.json, so we configure it here\n    const { resize_mode, fill_color, interpolation, size, ...other } = config;\n\n    const new_size =\n      resize_mode === 'squash'\n        ? { width: size, height: size }\n        : resize_mode === 'shortest'\n          ? { shortest_edge: size }\n          : { longest_edge: size };\n\n    const resample = interpolation === 'bicubic' ? 3 : 2;\n    super({\n      ...other,\n      size: new_size,\n      resample,\n      do_center_crop: true,\n      crop_size: size,\n      do_normalize: true,\n    });\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class LlavaOnevisionImageProcessor extends ImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\nimport { cat, interpolate_4d, slice, stack, Tensor } from '../../utils/tensor.js';\n\nconst IMAGE_SIZE = 336;\nconst SLICE_AXES = [2, 3]; // axes to slice on\nconst { ceil, floor, sqrt } = Math;\n\nexport class Phi3VImageProcessor extends ImageProcessor {\n  constructor(config) {\n    super({\n      ...config,\n      do_normalize: true,\n      do_pad: true,\n      pad_size: 'custom',\n      do_convert_rgb: true,\n      do_resize: true, // Smart resizing \"hd_transform\"\n    });\n\n    this._num_crops = config.num_crops;\n  }\n  calc_num_image_tokens_from_image_size(width, height) {\n    // @ts-expect-error\n    const { num_img_tokens } = this.config;\n    return floor(\n      (floor(height / IMAGE_SIZE) * floor(width / IMAGE_SIZE) + 1) * num_img_tokens +\n        1 +\n        (floor(height / IMAGE_SIZE) + 1) * sqrt(num_img_tokens),\n    );\n  }\n\n  /** @type {ImageProcessor['get_resize_output_image_size']} */\n  get_resize_output_image_size(image, size) {\n    const hd_num = this._num_crops;\n    const [width, height] = image.size;\n\n    let ratio = width / height;\n    let scale = 1;\n\n    // Calculate the scaling factor\n    while (scale * Math.ceil(scale / ratio) <= hd_num) {\n      scale += 1;\n    }\n    scale -= 1;\n\n    // Compute the new dimensions\n    const new_w = Math.floor(scale * 336);\n    const new_h = Math.floor(new_w / ratio);\n\n    return [new_w, new_h];\n  }\n\n  /** @type {ImageProcessor['pad_image']} */\n  pad_image(pixelData, imgDims, padSize, options = {}) {\n    // Phi3V uses a custom padding strategy:\n    // - Pad to a multiple of 336\n    // - Pad with white pixels\n    const [imageHeight, imageWidth] = imgDims;\n    const height = IMAGE_SIZE * ceil(imageHeight / IMAGE_SIZE);\n    const width = IMAGE_SIZE * ceil(imageWidth / IMAGE_SIZE);\n\n    // NOTE: Since padding is done after normalization, we need to fill with the normalized values\n    const constant_values = [1, 1, 1].map((x, i) => (x - this.image_mean[i]) / this.image_std[i]);\n    return super.pad_image(\n      pixelData,\n      imgDims,\n      { width, height },\n      {\n        center: true,\n        constant_values,\n        ...options,\n      },\n    );\n  }\n\n  async _call(images, { num_crops = null } = {}) {\n    // @ts-expect-error\n    this._num_crops = num_crops ??= this.config.num_crops;\n    if (num_crops < 4 || sqrt(num_crops) % 1 !== 0) {\n      throw new Error('num_crops must be a square number >= 4');\n    }\n\n    if (!Array.isArray(images)) {\n      images = [images];\n    }\n\n    const num_images = images.length;\n    const imageData = await Promise.all(images.map((x) => this.preprocess(x)));\n\n    const original_sizes = imageData.map((x) => x.original_size);\n    const reshaped_input_sizes = imageData.map((x) => x.reshaped_input_size);\n\n    // Process each image in batch\n    const all_pixel_values = [];\n    for (const { pixel_values } of imageData) {\n      pixel_values.unsqueeze_(0); // Easier processing as 4D tensor\n\n      const [height, width] = pixel_values.dims.slice(-2);\n\n      // Global image (Tensor of shape [num_channels, height, width])\n      const batch_pixel_values = await interpolate_4d(pixel_values, {\n        size: [IMAGE_SIZE, IMAGE_SIZE],\n        mode: 'bicubic',\n      });\n\n      if (num_crops > 0) {\n        const patches = [];\n        const sqrt_patches = sqrt(num_crops);\n        const patch_width = floor(width / sqrt_patches);\n        const patch_height = floor(height / sqrt_patches);\n        for (let y = 0; y < sqrt_patches; ++y) {\n          for (let x = 0; x < sqrt_patches; ++x) {\n            let start_x, start_y, end_x, end_y;\n            if (y === sqrt_patches - 1) {\n              // At bottom\n              start_y = height - patch_height;\n              end_y = height;\n            } else {\n              start_y = y * patch_height;\n              end_y = (y + 1) * patch_height;\n            }\n            if (x === sqrt_patches - 1) {\n              // At right\n              start_x = width - patch_width;\n              end_x = width;\n            } else {\n              start_x = x * patch_width;\n              end_x = (x + 1) * patch_width;\n            }\n\n            const starts = [start_y, start_x];\n            const ends = [end_y, end_x];\n            const patch = await slice(pixel_values, starts, ends, SLICE_AXES);\n            patches.push(patch);\n          }\n        }\n\n        const resized_tensors = await interpolate_4d(cat(patches, 0), {\n          size: [IMAGE_SIZE, IMAGE_SIZE],\n          mode: 'bicubic',\n        }); // [num_crops, 3, 336, 336]\n\n        // Concatenate the global image with the patches\n        all_pixel_values.push(cat([batch_pixel_values, resized_tensors], 0));\n      } else {\n        // Only use the global image\n        // NOTE: Not currently supported in modelling code\n        all_pixel_values.push(batch_pixel_values);\n      }\n    }\n\n    // [num_images, 1 + num_crops, num_channels=3, height, width]\n    const pixel_values = stack(all_pixel_values, 0);\n\n    // Calculate padded image sizes\n    const sizes = reshaped_input_sizes.map((x) => x.map((y) => IMAGE_SIZE * ceil(y / IMAGE_SIZE)));\n\n    const image_sizes = new Tensor('int64', sizes.flat(), [num_images, 2]);\n\n    const num_img_tokens = sizes.map(([height, width]) => this.calc_num_image_tokens_from_image_size(width, height));\n\n    return { pixel_values, original_sizes, reshaped_input_sizes, image_sizes, num_img_tokens };\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\nimport { cat, Tensor } from '../../utils/tensor.js';\n\nexport class Qwen2VLImageProcessor extends ImageProcessor {\n  async _call(images, ...args) {\n    const { pixel_values, original_sizes, reshaped_input_sizes } = await super._call(images, ...args);\n\n    let patches = pixel_values;\n\n    // @ts-ignore\n    const { temporal_patch_size, merge_size, patch_size } = this.config;\n    if (patches.dims[0] === 1) {\n      // Equivalent to np.tile(patches, (self.temporal_patch_size, 1, 1, 1))\n      patches = cat(\n        Array.from({ length: temporal_patch_size }, () => patches),\n        0,\n      );\n    }\n\n    const grid_t = patches.dims[0] / temporal_patch_size;\n    const channel = patches.dims[1];\n    const grid_h = Math.floor(patches.dims[2] / patch_size);\n    const grid_w = Math.floor(patches.dims[3] / patch_size);\n\n    const flatten_patches = patches\n      .view(\n        grid_t,\n        temporal_patch_size,\n        channel,\n        Math.floor(grid_h / merge_size),\n        merge_size,\n        patch_size,\n        Math.floor(grid_w / merge_size),\n        merge_size,\n        patch_size,\n      )\n      .permute(0, 3, 6, 4, 7, 2, 1, 5, 8)\n      .view(grid_t * grid_h * grid_w, channel * temporal_patch_size * patch_size * patch_size);\n\n    const image_grid_thw = new Tensor('int64', [grid_t, grid_h, grid_w], [1, 3]);\n\n    return {\n      pixel_values: flatten_patches,\n      image_grid_thw,\n      original_sizes,\n      reshaped_input_sizes,\n    };\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\nimport { calculateDimensions } from '../../utils/core.js';\n\nimport { interpolate_4d, Tensor } from '../../utils/tensor.js';\n\n/**\n * @typedef {object} SamImageProcessorResult\n * @property {Tensor} pixel_values\n * @property {import(\"../../base/image_processors_utils.js\").HeightWidth[]} original_sizes\n * @property {import(\"../../base/image_processors_utils.js\").HeightWidth[]} reshaped_input_sizes\n * @property {Tensor} [input_points]\n * @property {Tensor} [input_labels]\n * @property {Tensor} [input_boxes]\n */\n\nexport class SamImageProcessor extends ImageProcessor {\n  /**\n   *\n   * @param {any} input_points\n   * @param {import(\"../../base/image_processors_utils.js\").HeightWidth[]} original_sizes\n   * @param {import(\"../../base/image_processors_utils.js\").HeightWidth[]} reshaped_input_sizes\n   * @returns {Tensor}\n   */\n  reshape_input_points(input_points, original_sizes, reshaped_input_sizes, is_bounding_box = false) {\n    // Make deep copy to avoid altering user's input\n    input_points = structuredClone(input_points);\n    let shape = calculateDimensions(input_points);\n\n    // TODO: add support for 2D input_points\n    if (shape.length === 3) {\n      // Correct user's input\n      if (!is_bounding_box) {\n        shape = [1, ...shape];\n      }\n      input_points = [input_points];\n    } else if (shape.length !== 4) {\n      throw Error(\n        'The input_points must be a 4D tensor of shape `batch_size`, `point_batch_size`, `nb_points_per_image`, `2`.',\n      );\n    }\n\n    // Reshape input points\n    for (let i = 0; i < input_points.length; ++i) {\n      // batch_size\n      let originalImageSize = original_sizes[i];\n      let reshapedImageSize = reshaped_input_sizes[i];\n\n      let resizeFactors = [reshapedImageSize[0] / originalImageSize[0], reshapedImageSize[1] / originalImageSize[1]];\n\n      for (let j = 0; j < input_points[i].length; ++j) {\n        // point_batch_size\n        for (let k = 0; k < input_points[i][j].length; ++k) {\n          // nb_points_per_image\n          for (let w = 0; w < input_points[i][j][k].length; ++w) {\n            // 2 or 4\n            input_points[i][j][k][w] *= resizeFactors[w % 2];\n          }\n        }\n      }\n    }\n\n    return new Tensor('float32', Float32Array.from(input_points.flat(Infinity)), shape);\n  }\n\n  /**\n   *\n   * @param {any} input_labels\n   * @param {Tensor} input_points\n   * @returns {Tensor}\n   */\n  add_input_labels(input_labels, input_points) {\n    let shape = calculateDimensions(input_labels);\n    if (shape.length === 2) {\n      // Correct user's input\n      shape = [1, ...shape];\n      input_labels = [input_labels];\n    } else if (shape.length !== 3) {\n      throw Error(\n        'The input_points must be a 4D tensor of shape `batch_size`, `point_batch_size`, `nb_points_per_image`, `2`.',\n      );\n    }\n\n    if (shape.some((x, i) => x !== input_points.dims[i])) {\n      throw Error(`The first ${shape.length} dimensions of 'input_points' and 'input_labels' must be the same.`);\n    }\n    return new Tensor('int64', input_labels.flat(Infinity).map(BigInt), shape);\n  }\n  /**\n   * @param {any[]} images The URL(s) of the image(s) to extract features from.\n   * @param {Object} [options] Additional options for the processor.\n   * @param {any} [options.input_points=null] A 3D or 4D array, representing the input points provided by the user.\n   * - 3D: `[point_batch_size, nb_points_per_image, 2]`. In this case, `batch_size` is assumed to be 1.\n   * - 4D: `[batch_size, point_batch_size, nb_points_per_image, 2]`.\n   * @param {any} [options.input_labels=null] A 2D or 3D array, representing the input labels for the points, used by the prompt encoder to encode the prompt.\n   * - 2D: `[point_batch_size, nb_points_per_image]`. In this case, `batch_size` is assumed to be 1.\n   * - 3D: `[batch_size, point_batch_size, nb_points_per_image]`.\n   * @param {number[][][]} [options.input_boxes=null] A 3D array of shape `(batch_size, num_boxes, 4)`, representing the input boxes provided by the user.\n   * This is used by the prompt encoder to encode the prompt. Generally yields to much better generated masks.\n   * The processor will generate a tensor, with each dimension corresponding respectively to the image batch size,\n   * the number of boxes per image and the coordinates of the top left and botton right point of the box.\n   * In the order (`x1`, `y1`, `x2`, `y2`):\n   * - `x1`: the x coordinate of the top left point of the input box\n   * - `y1`: the y coordinate of the top left point of the input box\n   * - `x2`: the x coordinate of the bottom right point of the input box\n   * - `y2`: the y coordinate of the bottom right point of the input box\n   * @returns {Promise<SamImageProcessorResult>}\n   */\n  async _call(images, { input_points = null, input_labels = null, input_boxes = null } = {}) {\n    // TODO allow user to use preprocessed images\n    /** @type {SamImageProcessorResult} */\n    const processed = await super._call(images);\n\n    if (input_points) {\n      processed.input_points = this.reshape_input_points(\n        input_points,\n        processed.original_sizes,\n        processed.reshaped_input_sizes,\n      );\n    }\n\n    if (input_labels) {\n      if (!processed.input_points) {\n        throw Error('`input_points` must be provided if `input_labels` are provided.');\n      }\n      processed.input_labels = this.add_input_labels(input_labels, processed.input_points);\n    }\n\n    if (input_boxes) {\n      processed.input_boxes = this.reshape_input_points(\n        input_boxes,\n        processed.original_sizes,\n        processed.reshaped_input_sizes,\n        true,\n      );\n    }\n\n    return processed;\n  }\n\n  /**\n   * Remove padding and upscale masks to the original image size.\n   * @param {Tensor} masks Batched masks from the mask_decoder in (batch_size, num_channels, height, width) format.\n   * @param {[number, number][]} original_sizes The original sizes of each image before it was resized to the model's expected input shape, in (height, width) format.\n   * @param {[number, number][]} reshaped_input_sizes The size of each image as it is fed to the model, in (height, width) format. Used to remove padding.\n   * @param {Object} options Optional parameters for post-processing.\n   * @param {number} [options.mask_threshold] The threshold to use for binarizing the masks.\n   * @param {boolean} [options.binarize] Whether to binarize the masks.\n   * @param {Object} [options.pad_size] The target size the images were padded to before being passed to the model. If `null`, the target size is assumed to be the processor's `pad_size`.\n   * @param {number} [options.pad_size.height] The height the images were padded to.\n   * @param {number} [options.pad_size.width] The width the images were padded to.\n   * @returns {Promise<Tensor[]>} Batched masks in batch_size, num_channels, height, width) format, where (height, width) is given by original_size.\n   */\n  async post_process_masks(\n    masks,\n    original_sizes,\n    reshaped_input_sizes,\n    { mask_threshold = 0.0, binarize = true, pad_size = null } = {},\n  ) {\n    // masks: [1, 1, 3, 256, 256]\n\n    const output_masks = [];\n\n    pad_size = pad_size ?? this.pad_size;\n\n    /** @type {[number, number]} */\n    const target_image_size = [pad_size.height, pad_size.width];\n\n    for (let i = 0; i < original_sizes.length; ++i) {\n      const original_size = original_sizes[i];\n      const reshaped_input_size = reshaped_input_sizes[i];\n\n      // Upscale mask to padded size\n      let interpolated_mask = await interpolate_4d(masks[i], { mode: 'bilinear', size: target_image_size });\n\n      // Crop mask\n      interpolated_mask = interpolated_mask.slice(null, null, [0, reshaped_input_size[0]], [0, reshaped_input_size[1]]);\n\n      // Downscale mask\n      interpolated_mask = await interpolate_4d(interpolated_mask, { mode: 'bilinear', size: original_size });\n\n      if (binarize) {\n        const data = interpolated_mask.data;\n        const binarizedMaskData = new Uint8Array(data.length);\n        for (let i = 0; i < data.length; ++i) {\n          if (data[i] > mask_threshold) {\n            binarizedMaskData[i] = 1;\n          }\n        }\n        interpolated_mask = new Tensor('bool', binarizedMaskData, interpolated_mask.dims);\n      }\n\n      output_masks.push(interpolated_mask);\n    }\n\n    return output_masks;\n  }\n\n  /**\n   * Generates a list of crop boxes of different sizes. Each layer has (2**i)**2 boxes for the ith layer.\n   * @param {import(\"../../utils/image.js\").RawImage} image Input original image\n   * @param {number} target_size Target size of the resized image\n   * @param {Object} options Options for generating crop boxes\n   * @param {number} [options.crop_n_layers] If >0, mask prediction will be run again on crops of the image.\n   * Sets the number of layers to run, where each layer has 2**i_layer number of image crops.\n   * @param {number} [options.overlap_ratio] Sets the degree to which crops overlap. In the first crop layer,\n   * crops will overlap by this fraction of the image length. Later layers with more crops scale down this overlap.\n   * @param {number} [options.points_per_crop] Number of points to sample from each crop.\n   * @param {number} [options.crop_n_points_downscale_factor] The number of points-per-side sampled in layer n is\n   * scaled down by crop_n_points_downscale_factor**n.\n   * @returns {Object} An object containing the crop boxes, number of points per crop, cropped images, and input labels.\n   */\n  generate_crop_boxes(\n    image,\n    target_size,\n    { crop_n_layers = 0, overlap_ratio = 512 / 1500, points_per_crop = 32, crop_n_points_downscale_factor = 1 } = {},\n  ) {\n    // TODO: Implement\n    // return { crop_boxes, points_per_crop, cropped_images, input_labels }\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class SiglipImageProcessor extends ImageProcessor {}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class Swin2SRImageProcessor extends ImageProcessor {\n  pad_image(pixelData, imgDims, padSize, options = {}) {\n    // NOTE: In this case, `padSize` represents the size of the sliding window for the local attention.\n    // In other words, the image is padded so that its width and height are multiples of `padSize`.\n    const [imageHeight, imageWidth, imageChannels] = imgDims;\n\n    return super.pad_image(\n      pixelData,\n      imgDims,\n      {\n        // NOTE: For Swin2SR models, the original python implementation adds padding even when the image's width/height is already\n        // a multiple of `pad_size`. However, this is most likely a bug (PR: https://github.com/mv-lab/swin2sr/pull/19).\n        // For this reason, we only add padding when the image's width/height is not a multiple of `pad_size`.\n        width: imageWidth + ((padSize - (imageWidth % padSize)) % padSize),\n        height: imageHeight + ((padSize - (imageHeight % padSize)) % padSize),\n      },\n      {\n        mode: 'symmetric',\n        center: false,\n        constant_values: -1,\n        ...options,\n      },\n    );\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nimport { stack, cat } from '../../utils/tensor.js';\n\nexport class VitMatteImageProcessor extends ImageProcessor {\n  /**\n   * Calls the feature extraction process on an array of images, preprocesses\n   * each image, and concatenates the resulting features into a single Tensor.\n   * @param {import(\"../../utils/image.js\").RawImage[]} images The image(s) to extract features from.\n   * @param {import(\"../../utils/image.js\").RawImage[]} trimaps The trimaps(s) to extract features from.\n   * @returns {Promise<import(\"../../base/image_processors_utils.js\").ImageProcessorResult>} An object containing the concatenated pixel values of the preprocessed images.\n   */\n  async _call(images, trimaps) {\n    if (!Array.isArray(images)) {\n      images = [images];\n    }\n    if (!Array.isArray(trimaps)) {\n      trimaps = [trimaps];\n    }\n\n    const imageData = await Promise.all(images.map((x) => this.preprocess(x)));\n    const trimapData = await Promise.all(\n      trimaps.map((x) =>\n        this.preprocess(x, {\n          do_normalize: false,\n          do_convert_rgb: false,\n          do_convert_grayscale: true,\n        }),\n      ),\n    );\n\n    // Stack pixel values\n    const pixel_values = stack(\n      imageData.map(\n        // Concatenate images and trimaps\n        (x, i) => cat([x.pixel_values, trimapData[i].pixel_values], 0),\n      ),\n      0,\n    );\n\n    return {\n      pixel_values,\n\n      // Original sizes of images\n      original_sizes: imageData.map((x) => x.original_size),\n\n      // Reshaped sizes of images, before padding or cropping\n      reshaped_input_sizes: imageData.map((x) => x.reshaped_input_size),\n    };\n  }\n}\n","import { ImageProcessor } from '../../base/image_processors_utils.js';\n\nexport class VitPoseImageProcessor extends ImageProcessor {\n  /**\n   * Transform the heatmaps into keypoint predictions and transform them back to the image.\n   * NOTE: This is a naive implementation and does not include advanced post-processing techniques,\n   * so the results may not be as accurate as the original implementation.\n   * @param {import('../../utils/tensor.js').Tensor} outputs The model outputs.\n   * @param {[number, number, number, number][][]} boxes List or array of bounding boxes for each image.\n   * Each box should be a list of 4 floats representing the bounding box coordinates in COCO format (top_left_x, top_left_y, width, height).\n   * @returns {{\n   *   bbox: [number, number, number, number],\n   *   scores: number[],\n   *   labels: number[],\n   *   keypoints: [number, number][]\n   * }[][]} List of keypoints predictions for each image.\n   */\n  post_process_pose_estimation(\n    outputs,\n    boxes,\n    {\n      threshold = null,\n      // TODO:\n      // kernel_size = 11,\n      // target_sizes = null,\n    } = {},\n  ) {\n    // NOTE: boxes are 3D (batch_size, num_boxes, 4)\n    const heatmaps = outputs.tolist();\n    const [batch_size, num_classes, height, width] = outputs.dims;\n\n    const results = [];\n    for (let b = 0; b < batch_size; ++b) {\n      const heatmap = heatmaps[b];\n      const bboxes = boxes[b];\n\n      const batch_results = [];\n      for (let n = 0; n < bboxes.length; ++n) {\n        const bbox = bboxes[n];\n\n        const keypoints = [];\n        const scores = [];\n        const labels = [];\n\n        const xScale = bbox.at(-2) / width;\n        const yScale = bbox.at(-1) / height;\n        for (let c = 0; c < heatmap.length; ++c) {\n          let [xWeightedSum, yWeightedSum] = [0, 0];\n          let sum = 0;\n          let score = -Infinity;\n          const row = heatmap[c];\n          for (let y = 0; y < row.length; ++y) {\n            const col = row[y];\n            for (let x = 0; x < col.length; ++x) {\n              const value = col[x];\n              sum += value;\n\n              score = Math.max(score, value);\n\n              // Get weighted sum of positions\n              // TODO: Determine best offsets\n              xWeightedSum += (x + 0.5) * value;\n              yWeightedSum += y * value;\n            }\n          }\n\n          // Ignore low scores, if threshold is set\n          if (threshold != null && score < threshold) continue;\n\n          /** @type {[number, number]} */\n          const keypoint = [(xScale * xWeightedSum) / sum, (yScale * yWeightedSum) / sum];\n          keypoints.push(keypoint);\n          labels.push(c);\n          scores.push(score);\n        }\n        batch_results.push({\n          bbox,\n          scores,\n          labels,\n          keypoints,\n        });\n      }\n      results.push(batch_results);\n    }\n    return results;\n  }\n}\n","import { IMAGE_PROCESSOR_NAME } from '../../utils/constants.js';\nimport { getModelJSON } from '../../utils/hub.js';\nimport { Processor } from '../../base/processing_utils.js';\n\nimport * as AllProcessors from '../processors.js';\nimport * as AllImageProcessors from '../image_processors.js';\nimport * as AllFeatureExtractors from '../feature_extractors.js';\n\n/**\n * Helper class which is used to instantiate pretrained processors with the `from_pretrained` function.\n * The chosen processor class is determined by the type specified in the processor config.\n *\n * **Example:** Load a processor using `from_pretrained`.\n * ```javascript\n * let processor = await AutoProcessor.from_pretrained('openai/whisper-tiny.en');\n * ```\n *\n * **Example:** Run an image through a processor.\n * ```javascript\n * let processor = await AutoProcessor.from_pretrained('Xenova/clip-vit-base-patch16');\n * let image = await RawImage.read('https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg');\n * let image_inputs = await processor(image);\n * // {\n * //   \"pixel_values\": {\n * //     \"dims\": [ 1, 3, 224, 224 ],\n * //     \"type\": \"float32\",\n * //     \"data\": Float32Array [ -1.558687686920166, -1.558687686920166, -1.5440893173217773, ... ],\n * //     \"size\": 150528\n * //   },\n * //   \"original_sizes\": [\n * //     [ 533, 800 ]\n * //   ],\n * //   \"reshaped_input_sizes\": [\n * //     [ 224, 224 ]\n * //   ]\n * // }\n * ```\n */\nexport class AutoProcessor extends Processor {\n  /** @type {typeof Processor.from_pretrained} */\n  static async from_pretrained(pretrained_model_name_or_path: string, options = {}): Promise<Processor> {\n    // TODO: first check for processor.json\n    const preprocessorConfig = await getModelJSON(pretrained_model_name_or_path, IMAGE_PROCESSOR_NAME, true, options);\n\n    const { image_processor_type, feature_extractor_type, processor_class } = preprocessorConfig;\n    if (processor_class && AllProcessors[processor_class as keyof typeof AllProcessors]) {\n      return AllProcessors[processor_class as keyof typeof AllProcessors].from_pretrained(\n        pretrained_model_name_or_path,\n        options,\n      );\n    }\n\n    if (!image_processor_type && !feature_extractor_type) {\n      throw new Error('No `image_processor_type` or `feature_extractor_type` found in the config.');\n    }\n\n    const components: Record<string, any> = {};\n    if (image_processor_type) {\n      const image_processor_class = AllImageProcessors[image_processor_type as keyof typeof AllImageProcessors];\n      if (!image_processor_class) {\n        throw new Error(`Unknown image_processor_type: '${image_processor_type}'.`);\n      }\n      components.image_processor = new image_processor_class(preprocessorConfig);\n    }\n\n    if (feature_extractor_type) {\n      const image_processor_class = AllImageProcessors[feature_extractor_type as keyof typeof AllImageProcessors];\n      if (image_processor_class) {\n        // Handle legacy case where image processors were specified as feature extractors\n        components.image_processor = new image_processor_class(preprocessorConfig);\n      } else {\n        const feature_extractor_class =\n          AllFeatureExtractors[feature_extractor_type as keyof typeof AllFeatureExtractors];\n        if (!feature_extractor_class) {\n          throw new Error(`Unknown feature_extractor_type: '${feature_extractor_type}'.`);\n        }\n        components.feature_extractor = new feature_extractor_class(preprocessorConfig);\n      }\n    }\n\n    const config = {};\n    return new Processor(config, components);\n  }\n}\n","/**\n * @file Pipelines provide a high-level, easy to use, API for running machine learning models.\n *\n * **Example:** Instantiate pipeline using the `pipeline` function.\n * ```javascript\n * import { pipeline } from '@huggingface/transformers';\n *\n * const classifier = await pipeline('sentiment-analysis');\n * const output = await classifier('I love transformers!');\n * // [{'label': 'POSITIVE', 'score': 0.999817686}]\n * ```\n *\n * @module pipelines\n */\n\nimport { AutoTokenizer, PreTrainedTokenizer } from './tokenizers';\nimport {\n  AutoModel,\n  AutoModelForSpeechSeq2Seq,\n  AutoModelForTextToWaveform,\n  AutoModelForTextToSpectrogram,\n  AutoModelForCTC,\n  AutoModelForCausalLM,\n  AutoModelForVision2Seq,\n  AutoModelForImageToImage,\n  AutoModelForImageFeatureExtraction,\n  PreTrainedModel,\n} from './models';\nimport { AutoProcessor } from './models/auto/processing_auto';\nimport { Processor } from './base/processing_utils';\n\nimport { Callable } from './utils/generic.js';\n\nimport { dispatchCallback, product } from './utils/core';\nimport { softmax, max, round } from './utils/maths';\nimport { read_audio, RawAudio } from './utils/audio';\nimport { Tensor, mean_pooling, interpolate_4d, quantize_embeddings, topk } from './utils/tensor';\nimport { RawImage } from './utils/image';\nimport { PretrainedOptions } from './utils/hub';\nimport { ImagePipelineConstructorArgs, Message, TextGenerationOutput, TextImagePipelineConstructorArgs } from './types';\nimport {\n  ImageFeatureExtractionPipelineOptions,\n  ImagePipelineInputs,\n  AudioPipelineInputs,\n  TextPipelineConstructorArgs,\n  PipelineType,\n  TextAudioPipelineConstructorArgs,\n} from './types';\n/**\n * @typedef {string | RawImage | URL} ImageInput\n * @typedef {ImageInput|ImageInput[]} ImagePipelineInputs\n */\n\n/**\n * Prepare images for further tasks.\n * @param {ImagePipelineInputs} images images to prepare.\n * @returns {Promise<RawImage[]>} returns processed images.\n * @private\n */\n\nasync function prepareImages(images: ImagePipelineInputs) {\n  if (!Array.isArray(images)) {\n    images = [images];\n  }\n\n  // Possibly convert any non-images to images\n  return await Promise.all(images.map((x) => RawImage.read(x)));\n}\n\n/**\n * @typedef {string | URL | Float32Array | Float64Array} AudioInput\n * @typedef {AudioInput|AudioInput[]} AudioPipelineInputs\n */\n\ntype AudioInput = string | URL | Float32Array | Float64Array;\n\n/**\n * Prepare audios for further tasks.\n * @param {AudioPipelineInputs} audios audios to prepare.\n * @param {number} sampling_rate sampling rate of the audios.\n * @returns {Promise<Float32Array[]>} The preprocessed audio data.\n * @private\n */\nasync function prepareAudios(audios: AudioPipelineInputs, sampling_rate: number) {\n  if (!Array.isArray(audios)) {\n    audios = [audios];\n  }\n\n  return await Promise.all(\n    audios.map((x) => {\n      if (typeof x === 'string' || x instanceof URL) {\n        return read_audio(x, sampling_rate);\n      } else if (x instanceof Float64Array) {\n        return new Float32Array(x);\n      }\n      return x;\n    }),\n  );\n}\n\n/**\n * @typedef {Object} BoundingBox\n * @property {number} xmin The minimum x coordinate of the bounding box.\n * @property {number} ymin The minimum y coordinate of the bounding box.\n * @property {number} xmax The maximum x coordinate of the bounding box.\n * @property {number} ymax The maximum y coordinate of the bounding box.\n */\n\n/**\n * Helper function to convert list [xmin, xmax, ymin, ymax] into object { \"xmin\": xmin, ... }\n * @param {number[]} box The bounding box as a list.\n * @param {boolean} asInteger Whether to cast to integers.\n * @returns {BoundingBox} The bounding box as an object.\n * @private\n */\nfunction get_bounding_box(box: number[], asInteger: boolean) {\n  if (asInteger) {\n    box = box.map((x) => x | 0);\n  }\n  const [xmin, ymin, xmax, ymax] = box;\n\n  return { xmin, ymin, xmax, ymax };\n}\n\n/**\n * @callback DisposeType Disposes the item.\n * @returns {Promise<void>} A promise that resolves when the item has been disposed.\n *\n * @typedef {Object} Disposable\n * @property {DisposeType} dispose A promise that resolves when the pipeline has been disposed.\n */\n\n/**\n * The Pipeline class is the class from which all pipelines inherit.\n * Refer to this class for methods shared across different pipelines.\n */\nexport abstract class Pipeline extends Callable {\n  /**\n   * Create a new Pipeline.\n   * @param {Object} options An object containing the following properties:\n   * @param {string} [options.task] The task of the pipeline. Useful for specifying subtasks.\n   * @param {PreTrainedModel} [options.model] The model used by the pipeline.\n   * @param {PreTrainedTokenizer} [options.tokenizer=null] The tokenizer used by the pipeline (if any).\n   * @param {Processor} [options.processor=null] The processor used by the pipeline (if any).\n   */\n  task: string;\n  model: PreTrainedModel;\n  tokenizer: PreTrainedTokenizer | null;\n  processor: Processor | null;\n\n  constructor({\n    task,\n    model,\n    tokenizer = null,\n    processor = null,\n  }: {\n    task: string;\n    model: PreTrainedModel;\n    tokenizer?: PreTrainedTokenizer | null;\n    processor?: Processor | null;\n  }) {\n    super();\n    this.task = task;\n    this.model = model;\n    this.tokenizer = tokenizer;\n    this.processor = processor;\n  }\n\n  async dispose(): Promise<void> {\n    await this.model.dispose();\n  }\n\n  public abstract _call(...args: any[]): Promise<any>;\n}\n\n/**\n * @typedef {Object} ModelTokenizerConstructorArgs\n * @property {string} task The task of the pipeline. Useful for specifying subtasks.\n * @property {PreTrainedModel} model The model used by the pipeline.\n * @property {PreTrainedTokenizer} tokenizer The tokenizer used by the pipeline.\n *\n * @typedef {ModelTokenizerConstructorArgs} TextPipelineConstructorArgs An object used to instantiate a text-based pipeline.\n */\n\n/**\n * @typedef {Object} ModelProcessorConstructorArgs\n * @property {string} task The task of the pipeline. Useful for specifying subtasks.\n * @property {PreTrainedModel} model The model used by the pipeline.\n * @property {Processor} processor The processor used by the pipeline.\n *\n * @typedef {ModelProcessorConstructorArgs} AudioPipelineConstructorArgs An object used to instantiate an audio-based pipeline.\n * @typedef {ModelProcessorConstructorArgs} ImagePipelineConstructorArgs An object used to instantiate an image-based pipeline.\n */\n\n/**\n * @typedef {Object} ModelTokenizerProcessorConstructorArgs\n * @property {string} task The task of the pipeline. Useful for specifying subtasks.\n * @property {PreTrainedModel} model The model used by the pipeline.\n * @property {PreTrainedTokenizer} tokenizer The tokenizer used by the pipeline.\n * @property {Processor} processor The processor used by the pipeline.\n *\n * @typedef {ModelTokenizerProcessorConstructorArgs} TextAudioPipelineConstructorArgs An object used to instantiate a text- and audio-based pipeline.\n * @typedef {ModelTokenizerProcessorConstructorArgs} TextImagePipelineConstructorArgs An object used to instantiate a text- and image-based pipeline.\n */\n\n/**\n * @typedef {import('./tokenizers.js').Message[]} Chat\n *\n * @typedef {Object} TextGenerationSingle\n * @property {string|Chat} generated_text The generated text.\n * @typedef {TextGenerationSingle[]} TextGenerationOutput\n *\n * @typedef {Object} TextGenerationSpecificParams Parameters specific to text-generation pipelines.\n * @property {boolean} [add_special_tokens] Whether or not to add special tokens when tokenizing the sequences.\n * @property {boolean} [return_full_text=true] If set to `false` only added text is returned, otherwise the full text is returned.\n * @typedef {import('./generation/configuration_utils.js').GenerationConfig & TextGenerationSpecificParams} TextGenerationConfig\n *\n * @callback TextGenerationPipelineCallback Complete the prompt(s) given as inputs.\n * @param {string|string[]|Chat|Chat[]} texts One or several prompts (or one list of prompts) to complete.\n * @param {Partial<TextGenerationConfig>} [options] Additional keyword arguments to pass along to the generate method of the model.\n * @returns {Promise<TextGenerationOutput|TextGenerationOutput[]>} An array or object containing the generated texts.\n *\n * @typedef {TextPipelineConstructorArgs & TextGenerationPipelineCallback & Disposable} TextGenerationPipelineType\n */\n\n/**\n * Language generation pipeline using any `ModelWithLMHead` or `ModelForCausalLM`.\n * This pipeline predicts the words that will follow a specified text prompt.\n * NOTE: For the full list of generation parameters, see [`GenerationConfig`](./utils/generation#module_utils/generation.GenerationConfig).\n *\n * **Example:** Text generation with `Xenova/distilgpt2` (default settings).\n * ```javascript\n * const generator = await pipeline('text-generation', 'Xenova/distilgpt2');\n * const text = 'I enjoy walking with my cute dog,';\n * const output = await generator(text);\n * // [{ generated_text: \"I enjoy walking with my cute dog, and I love to play with the other dogs.\" }]\n * ```\n *\n * **Example:** Text generation with `Xenova/distilgpt2` (custom settings).\n * ```javascript\n * const generator = await pipeline('text-generation', 'Xenova/distilgpt2');\n * const text = 'Once upon a time, there was';\n * const output = await generator(text, {\n *   temperature: 2,\n *   max_new_tokens: 10,\n *   repetition_penalty: 1.5,\n *   no_repeat_ngram_size: 2,\n *   num_beams: 2,\n *   num_return_sequences: 2,\n * });\n * // [{\n * //   \"generated_text\": \"Once upon a time, there was an abundance of information about the history and activities that\"\n * // }, {\n * //   \"generated_text\": \"Once upon a time, there was an abundance of information about the most important and influential\"\n * // }]\n * ```\n *\n * **Example:** Run code generation with `Xenova/codegen-350M-mono`.\n * ```javascript\n * const generator = await pipeline('text-generation', 'Xenova/codegen-350M-mono');\n * const text = 'def fib(n):';\n * const output = await generator(text, {\n *   max_new_tokens: 44,\n * });\n * // [{\n * //   generated_text: 'def fib(n):\\n' +\n * //     '    if n == 0:\\n' +\n * //     '        return 0\\n' +\n * //     '    elif n == 1:\\n' +\n * //     '        return 1\\n' +\n * //     '    else:\\n' +\n * //     '        return fib(n-1) + fib(n-2)\\n'\n * // }]\n * ```\n */\ntype Chat = Message[];\nexport class TextGenerationPipeline\n  extends /** @type {new (options: TextPipelineConstructorArgs) => TextGenerationPipelineType} */ Pipeline\n{\n  /**\n   * Create a new TextGenerationPipeline.\n   * @param {TextPipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  constructor(options: TextPipelineConstructorArgs) {\n    super(options);\n  }\n\n  /** @type {TextGenerationPipelineCallback} */\n  async _call(texts: string | string[] | Chat | Chat[], generate_kwargs = {}) {\n    let isBatched = false;\n    let isChatInput = false;\n\n    // Normalize inputs\n    /** @type {string[]} */\n    let inputs;\n    if (typeof texts === 'string') {\n      inputs = texts = [texts];\n    } else if (Array.isArray(texts) && texts.every((x) => typeof x === 'string')) {\n      isBatched = true;\n      inputs = /** @type {string[]} */ texts;\n    } else {\n      if (isChat(texts)) {\n        texts = [texts as Chat];\n      } else if (Array.isArray(texts) && texts.every(isChat)) {\n        isBatched = true;\n      } else {\n        throw new Error('Input must be a string, an array of strings, a Chat, or an array of Chats');\n      }\n      isChatInput = true;\n\n      // If the input is a chat, we need to apply the chat template\n      inputs = /** @type {string[]} */ /** @type {Chat[]} */ texts.map((x: any) =>\n        this.tokenizer!.apply_chat_template(x, {\n          tokenize: false,\n          add_generation_prompt: true,\n        }),\n      );\n    }\n\n    // By default, do not add special tokens\n    const add_special_tokens = (generate_kwargs as any).add_special_tokens ?? false;\n\n    // By default, return full text\n    const return_full_text = isChatInput ? false : ((generate_kwargs as any).return_full_text ?? true);\n\n    this.tokenizer!.padding_side = 'left';\n    const model_inputs = (this.tokenizer as any)(texts, {\n      add_special_tokens,\n      padding: true,\n      truncation: true,\n    } as any);\n\n    const outputTokenIds = /** @type {Tensor} */ await this.model.generate({\n      ...model_inputs,\n      ...generate_kwargs,\n    });\n\n    const decoded = (this.tokenizer as any).batch_decode(outputTokenIds, {\n      skip_special_tokens: true,\n    });\n\n    let promptLengths;\n    if (!return_full_text && (model_inputs as any).input_ids.dims.at(-1) > 0) {\n      promptLengths = (this.tokenizer as any)\n        .batch_decode((model_inputs as any).input_ids, {\n          skip_special_tokens: true,\n        })\n        .map((x: any) => x.length);\n    }\n\n    /** @type {TextGenerationOutput[]} */\n    const toReturn: TextGenerationOutput[] = Array.from({ length: texts.length }, (_) => []);\n    for (let i = 0; i < (decoded as any).length; ++i) {\n      const textIndex = Math.floor((i / (outputTokenIds as any).dims[0]) * texts.length);\n\n      if (promptLengths) {\n        // Trim the decoded text to only include the generated part\n        decoded[i] = (decoded as any)[i].slice(promptLengths[textIndex]);\n      }\n      toReturn[textIndex].push({\n        generated_text: isChatInput\n          ? [.../** @type {Chat[]} */ texts[textIndex], { role: 'assistant', content: decoded[i] }]\n          : decoded[i],\n      });\n    }\n    return !isBatched && toReturn.length === 1 ? toReturn[0] : toReturn;\n  }\n}\n\n/**\n * @typedef {Object} FeatureExtractionPipelineOptions Parameters specific to feature extraction pipelines.\n * @property {'none'|'mean'|'cls'} [pooling=\"none\"] The pooling method to use.\n * @property {boolean} [normalize=false] Whether or not to normalize the embeddings in the last dimension.\n * @property {boolean} [quantize=false] Whether or not to quantize the embeddings.\n * @property {'binary'|'ubinary'} [precision='binary'] The precision to use for quantization.\n *\n * @callback FeatureExtractionPipelineCallback Extract the features of the input(s).\n * @param {string|string[]} texts One or several texts (or one list of texts) to get the features of.\n * @param {FeatureExtractionPipelineOptions} [options] The options to use for feature extraction.\n * @returns {Promise<Tensor>} The features computed by the model.\n *\n * @typedef {TextPipelineConstructorArgs & FeatureExtractionPipelineCallback & Disposable} FeatureExtractionPipelineType\n */\n\n/**\n * Feature extraction pipeline using no model head. This pipeline extracts the hidden\n * states from the base transformer, which can be used as features in downstream tasks.\n *\n * **Example:** Run feature extraction with `bert-base-uncased` (without pooling/normalization).\n * ```javascript\n * const extractor = await pipeline('feature-extraction', 'Xenova/bert-base-uncased', { revision: 'default' });\n * const output = await extractor('This is a simple test.');\n * // Tensor {\n * //   type: 'float32',\n * //   data: Float32Array [0.05939924716949463, 0.021655935794115067, ...],\n * //   dims: [1, 8, 768]\n * // }\n * ```\n *\n * **Example:** Run feature extraction with `bert-base-uncased` (with pooling/normalization).\n * ```javascript\n * const extractor = await pipeline('feature-extraction', 'Xenova/bert-base-uncased', { revision: 'default' });\n * const output = await extractor('This is a simple test.', { pooling: 'mean', normalize: true });\n * // Tensor {\n * //   type: 'float32',\n * //   data: Float32Array [0.03373778983950615, -0.010106077417731285, ...],\n * //   dims: [1, 768]\n * // }\n * ```\n *\n * **Example:** Calculating embeddings with `sentence-transformers` models.\n * ```javascript\n * const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');\n * const output = await extractor('This is a simple test.', { pooling: 'mean', normalize: true });\n * // Tensor {\n * //   type: 'float32',\n * //   data: Float32Array [0.09094982594251633, -0.014774246141314507, ...],\n * //   dims: [1, 384]\n * // }\n * ```\n * **Example:** Calculating binary embeddings with `sentence-transformers` models.\n * ```javascript\n * const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');\n * const output = await extractor('This is a simple test.', { pooling: 'mean', quantize: true, precision: 'binary' });\n * // Tensor {\n * //   type: 'int8',\n * //   data: Int8Array [49, 108, 24, ...],\n * //   dims: [1, 48]\n * // }\n * ```\n */\nexport class FeatureExtractionPipeline\n  extends /** @type {new (options: TextPipelineConstructorArgs) => FeatureExtractionPipelineType} */ Pipeline\n{\n  /**\n   * Create a new FeatureExtractionPipeline.\n   * @param {TextPipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  constructor(options: TextPipelineConstructorArgs) {\n    super(options);\n  }\n\n  /** @type {FeatureExtractionPipelineCallback} */\n  async _call(\n    texts: string | string[],\n    {\n      pooling = /** @type {'none'} */ 'none',\n      normalize = false,\n      quantize = false,\n      precision = /** @type {'binary'} */ 'binary',\n    } = {},\n  ) {\n    // Run tokenization\n    const model_inputs = (this.tokenizer as any)(texts, {\n      padding: true,\n      truncation: true,\n    });\n\n    // Run model\n    const outputs = await (this.model as any)(model_inputs);\n\n    // TODO: Provide warning to the user that they might be using model which was not exported\n    // specifically for feature extraction\n    // console.log(this.model.config)\n    // console.log(outputs)\n\n    /** @type {Tensor} */\n    let result = outputs.last_hidden_state ?? outputs.logits ?? outputs.token_embeddings;\n    if (pooling === 'none') {\n      // Skip pooling\n    } else if (pooling === 'mean') {\n      result = mean_pooling(result, model_inputs.attention_mask);\n    } else if (pooling === 'cls') {\n      result = result.slice(null, 0);\n    } else {\n      throw Error(`Pooling method '${pooling}' not supported.`);\n    }\n\n    if (normalize) {\n      result = result.normalize(2, -1);\n    }\n\n    if (quantize) {\n      result = quantize_embeddings(result, precision as any);\n    }\n\n    return result;\n  }\n}\n\n/**\n * @typedef {Object} ImageFeatureExtractionPipelineOptions Parameters specific to image feature extraction pipelines.\n * @property {boolean} [pool=null] Whether or not to return the pooled output. If set to `false`, the model will return the raw hidden states.\n *\n * @callback ImageFeatureExtractionPipelineCallback Extract the features of the input(s).\n * @param {ImagePipelineInputs} images One or several images (or one list of images) to get the features of.\n * @param {ImageFeatureExtractionPipelineOptions} [options] The options to use for image feature extraction.\n * @returns {Promise<Tensor>} The image features computed by the model.\n *\n * @typedef {ImagePipelineConstructorArgs & ImageFeatureExtractionPipelineCallback & Disposable} ImageFeatureExtractionPipelineType\n */\n\n/**\n * Image feature extraction pipeline using no model head. This pipeline extracts the hidden\n * states from the base transformer, which can be used as features in downstream tasks.\n *\n * **Example:** Perform image feature extraction with `Xenova/vit-base-patch16-224-in21k`.\n * ```javascript\n * const image_feature_extractor = await pipeline('image-feature-extraction', 'Xenova/vit-base-patch16-224-in21k');\n * const url = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png';\n * const features = await image_feature_extractor(url);\n * // Tensor {\n * //   dims: [ 1, 197, 768 ],\n * //   type: 'float32',\n * //   data: Float32Array(151296) [ ... ],\n * //   size: 151296\n * // }\n * ```\n *\n * **Example:** Compute image embeddings with `Xenova/clip-vit-base-patch32`.\n * ```javascript\n * const image_feature_extractor = await pipeline('image-feature-extraction', 'Xenova/clip-vit-base-patch32');\n * const url = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png';\n * const features = await image_feature_extractor(url);\n * // Tensor {\n * //   dims: [ 1, 512 ],\n * //   type: 'float32',\n * //   data: Float32Array(512) [ ... ],\n * //   size: 512\n * // }\n * ```\n */\nexport class ImageFeatureExtractionPipeline\n  extends /** @type {new (options: ImagePipelineConstructorArgs) => ImageFeatureExtractionPipelineType} */ Pipeline\n{\n  /**\n   * Create a new ImageFeatureExtractionPipeline.\n   * @param {ImagePipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  constructor(options: ImagePipelineConstructorArgs) {\n    super(options);\n  }\n\n  /** @type {ImageFeatureExtractionPipelineCallback} */\n  async _call(images: ImagePipelineInputs, { pool = null } = {}) {\n    const preparedImages = await prepareImages(images);\n    const { pixel_values } = await (this.processor as any)(preparedImages);\n    const outputs = await (this.model as any)({ pixel_values });\n\n    /** @type {Tensor} */\n    let result;\n    if (pool) {\n      if (!('pooler_output' in outputs)) {\n        throw Error(\n          `No pooled output was returned. Make sure the model has a 'pooler' layer when using the 'pool' option.`,\n        );\n      }\n      result = outputs.pooler_output;\n    } else {\n      result = outputs.last_hidden_state ?? outputs.logits ?? outputs.image_embeds;\n    }\n    return result;\n  }\n}\n\n/**\n * @typedef {Object} Chunk\n * @property {[number, number]} timestamp The start and end timestamp of the chunk in seconds.\n * @property {string} text The recognized text.\n */\n\n/**\n * @typedef {Object} AutomaticSpeechRecognitionOutput\n * @property {string} text The recognized text.\n * @property {Chunk[]} [chunks] When using `return_timestamps`, the `chunks` will become a list\n * containing all the various text chunks identified by the model.\n *\n * @typedef {Object} AutomaticSpeechRecognitionSpecificParams Parameters specific to automatic-speech-recognition pipelines.\n * @property {boolean|'word'} [return_timestamps] Whether to return timestamps or not. Default is `false`.\n * @property {number} [chunk_length_s] The length of audio chunks to process in seconds. Default is 0 (no chunking).\n * @property {number} [stride_length_s] The length of overlap between consecutive audio chunks in seconds. If not provided, defaults to `chunk_length_s / 6`.\n * @property {boolean} [force_full_sequences] Whether to force outputting full sequences or not. Default is `false`.\n * @property {string} [language] The source language. Default is `null`, meaning it should be auto-detected. Use this to potentially improve performance if the source language is known.\n * @property {string} [task] The task to perform. Default is `null`, meaning it should be auto-detected.\n * @property {number} [num_frames] The number of frames in the input audio.\n * @typedef {import('./generation/configuration_utils.js').GenerationConfig & AutomaticSpeechRecognitionSpecificParams} AutomaticSpeechRecognitionConfig\n *\n * @callback AutomaticSpeechRecognitionPipelineCallback Transcribe the audio sequence(s) given as inputs to text.\n * @param {AudioPipelineInputs} audio The input audio file(s) to be transcribed. The input is either:\n * - `string` or `URL` that is the filename/URL of the audio file, the file will be read at the processor's sampling rate\n * to get the waveform using the [`AudioContext`](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext) API.\n * If `AudioContext` is not available, you should pass the raw waveform in as a Float32Array of shape `(n, )`.\n * - `Float32Array` or `Float64Array` of shape `(n, )`, representing the raw audio at the correct sampling rate (no further check will be done).\n * @param {Partial<AutomaticSpeechRecognitionConfig>} [options] Additional keyword arguments to pass along to the generate method of the model.\n * @returns {Promise<AutomaticSpeechRecognitionOutput|AutomaticSpeechRecognitionOutput[]>} An object containing the transcription text and optionally timestamps if `return_timestamps` is `true`.\n *\n * @typedef {TextAudioPipelineConstructorArgs & AutomaticSpeechRecognitionPipelineCallback & Disposable} AutomaticSpeechRecognitionPipelineType\n */\n\ninterface Chunk {\n  timestamp: [number, number];\n  text: string;\n}\n\ninterface AutomaticSpeechRecognitionOutput {\n  text: string;\n  chunks?: Chunk[];\n}\n\ninterface AutomaticSpeechRecognitionSpecificParams {\n  return_timestamps?: boolean | 'word';\n  chunk_length_s?: number;\n  stride_length_s?: number;\n  force_full_sequences?: boolean;\n  language?: string;\n  task?: string;\n  num_frames?: number;\n}\n\ntype AutomaticSpeechRecognitionConfig = import('./generation/configuration_utils.js').GenerationConfig &\n  AutomaticSpeechRecognitionSpecificParams;\n\ntype AutomaticSpeechRecognitionPipelineCallback = (\n  audio: AudioPipelineInputs,\n  options?: Partial<AutomaticSpeechRecognitionConfig>,\n) => Promise<AutomaticSpeechRecognitionOutput | AutomaticSpeechRecognitionOutput[]>;\n\ntype AutomaticSpeechRecognitionPipelineType = TextAudioPipelineConstructorArgs &\n  AutomaticSpeechRecognitionPipelineCallback &\n  Disposable;\n\n/**\n * Pipeline that aims at extracting spoken text contained within some audio.\n *\n * **Example:** Transcribe English.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-tiny.en');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav';\n * const output = await transcriber(url);\n * // { text: \" And so my fellow Americans ask not what your country can do for you, ask what you can do for your country.\" }\n * ```\n *\n * **Example:** Transcribe English w/ timestamps.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-tiny.en');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav';\n * const output = await transcriber(url, { return_timestamps: true });\n * // {\n * //   text: \" And so my fellow Americans ask not what your country can do for you, ask what you can do for your country.\"\n * //   chunks: [\n * //     { timestamp: [0, 8],  text: \" And so my fellow Americans ask not what your country can do for you\" }\n * //     { timestamp: [8, 11], text: \" ask what you can do for your country.\" }\n * //   ]\n * // }\n * ```\n *\n * **Example:** Transcribe English w/ word-level timestamps.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-tiny.en');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/jfk.wav';\n * const output = await transcriber(url, { return_timestamps: 'word' });\n * // {\n * //   \"text\": \" And so my fellow Americans ask not what your country can do for you ask what you can do for your country.\",\n * //   \"chunks\": [\n * //     { \"text\": \" And\", \"timestamp\": [0, 0.78] },\n * //     { \"text\": \" so\", \"timestamp\": [0.78, 1.06] },\n * //     { \"text\": \" my\", \"timestamp\": [1.06, 1.46] },\n * //     ...\n * //     { \"text\": \" for\", \"timestamp\": [9.72, 9.92] },\n * //     { \"text\": \" your\", \"timestamp\": [9.92, 10.22] },\n * //     { \"text\": \" country.\", \"timestamp\": [10.22, 13.5] }\n * //   ]\n * // }\n * ```\n *\n * **Example:** Transcribe French.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-small');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/french-audio.mp3';\n * const output = await transcriber(url, { language: 'french', task: 'transcribe' });\n * // { text: \" J'adore, j'aime, je n'aime pas, je déteste.\" }\n * ```\n *\n * **Example:** Translate French to English.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-small');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/french-audio.mp3';\n * const output = await transcriber(url, { language: 'french', task: 'translate' });\n * // { text: \" I love, I like, I don't like, I hate.\" }\n * ```\n *\n * **Example:** Transcribe/translate audio longer than 30 seconds.\n * ```javascript\n * const transcriber = await pipeline('automatic-speech-recognition', 'Xenova/whisper-tiny.en');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/ted_60.wav';\n * const output = await transcriber(url, { chunk_length_s: 30, stride_length_s: 5 });\n * // { text: \" So in college, I was a government major, which means [...] So I'd start off light and I'd bump it up\" }\n * ```\n */\nexport class AutomaticSpeechRecognitionPipeline\n  extends /** @type {new (options: TextAudioPipelineConstructorArgs) => AutomaticSpeechRecognitionPipelineType} */ Pipeline\n{\n  /**\n   * Create a new AutomaticSpeechRecognitionPipeline.\n   * @param {TextAudioPipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  constructor(options: TextAudioPipelineConstructorArgs) {\n    super(options);\n  }\n\n  /** @type {AutomaticSpeechRecognitionPipelineCallback} */\n  async _call(audio: AudioPipelineInputs, kwargs = {}) {\n    switch ((this.model as any).config.model_type) {\n      case 'whisper':\n        return this._call_whisper(audio, kwargs);\n      case 'wav2vec2':\n      case 'wav2vec2-bert':\n      case 'unispeech':\n      case 'unispeech-sat':\n      case 'hubert':\n        return this._call_wav2vec2(audio, kwargs);\n      case 'moonshine':\n        return this._call_moonshine(audio, kwargs);\n      default:\n        throw new Error(\n          `AutomaticSpeechRecognitionPipeline does not support model type '${this.model.config.model_type}'.`,\n        );\n    }\n  }\n\n  /**\n   * @type {AutomaticSpeechRecognitionPipelineCallback}\n   * @private\n   */\n  async _call_wav2vec2(audio: AudioPipelineInputs, kwargs: Partial<AutomaticSpeechRecognitionConfig>) {\n    // TODO use kwargs\n\n    if (kwargs.language) {\n      console.warn('`language` parameter is not yet supported for `wav2vec2` models, defaulting to \"English\".');\n    }\n    if (kwargs.task) {\n      console.warn('`task` parameter is not yet supported for `wav2vec2` models, defaulting to \"transcribe\".');\n    }\n\n    const single = !Array.isArray(audio);\n    if (single) {\n      audio = [audio as AudioInput];\n    }\n\n    const sampling_rate = (this.processor as any).feature_extractor.config.sampling_rate;\n    const preparedAudios = await prepareAudios(audio, sampling_rate);\n\n    const toReturn = [];\n    for (const aud of preparedAudios) {\n      const inputs = await (this.processor as any)(aud);\n      const output = await (this.model as any)(inputs);\n      const logits = output.logits[0];\n\n      const predicted_ids = [];\n      for (const item of logits) {\n        predicted_ids.push(max(item.data)[1]);\n      }\n      const predicted_sentences = (this.tokenizer as any).decode(predicted_ids);\n      toReturn.push({ text: predicted_sentences });\n    }\n    return single ? toReturn[0] : toReturn;\n  }\n\n  /**\n   * @type {AutomaticSpeechRecognitionPipelineCallback}\n   * @private\n   */\n  async _call_whisper(audio: AudioPipelineInputs, kwargs: Partial<AutomaticSpeechRecognitionConfig>) {\n    const return_timestamps = kwargs.return_timestamps ?? false;\n    const chunk_length_s = kwargs.chunk_length_s ?? 0;\n    const force_full_sequences = kwargs.force_full_sequences ?? false;\n    let stride_length_s = kwargs.stride_length_s ?? null;\n\n    const generation_config = { ...kwargs };\n\n    if (return_timestamps === 'word') {\n      (generation_config as any)['return_token_timestamps'] = true;\n      generation_config['return_timestamps'] = false; // Do not predict timestamp tokens\n    }\n\n    const single = !Array.isArray(audio);\n    if (single) {\n      audio = [audio as AudioInput];\n    }\n\n    const time_precision =\n      (this.processor as any).feature_extractor.config.chunk_length / (this.model as any).config.max_source_positions;\n    const hop_length = (this.processor as any).feature_extractor.config.hop_length;\n\n    const sampling_rate = (this.processor as any).feature_extractor.config.sampling_rate;\n    const preparedAudios = await prepareAudios(audio, sampling_rate);\n\n    const toReturn = [];\n    for (const aud of preparedAudios) {\n      /** @type {{stride: number[], input_features: Tensor, is_last: boolean, tokens?: bigint[], token_timestamps?: number[]}[]} */\n      let chunks = [];\n      if (chunk_length_s > 0) {\n        if (stride_length_s === null) {\n          stride_length_s = chunk_length_s / 6;\n        } else if (chunk_length_s <= stride_length_s) {\n          throw Error('`chunk_length_s` must be larger than `stride_length_s`.');\n        }\n\n        // TODO support different stride_length_s (for left and right)\n\n        const window = sampling_rate * chunk_length_s;\n        const stride = sampling_rate * stride_length_s;\n        const jump = window - 2 * stride;\n        let offset = 0;\n\n        // Create subarrays of audio with overlaps\n        while (true) {\n          const offset_end = offset + window;\n          const subarr = aud.subarray(offset, offset_end);\n          const feature = await (this.processor as any)(subarr);\n\n          const is_first = offset === 0;\n          const is_last = offset_end >= aud.length;\n          chunks.push({\n            stride: [subarr.length, is_first ? 0 : stride, is_last ? 0 : stride],\n            input_features: feature.input_features,\n            is_last,\n          });\n          if (is_last) break;\n          offset += jump;\n        }\n      } else {\n        chunks = [\n          {\n            stride: [aud.length, 0, 0],\n            input_features: (await (this.processor as any)(aud)).input_features,\n            is_last: true,\n            tokens: [],\n          },\n        ];\n      }\n\n      // Generate for each set of input features\n      for (const chunk of chunks) {\n        generation_config.num_frames = Math.floor(chunk.stride[0] / hop_length);\n        // console.log(generation_config, chunk);\n        // NOTE: doing sequentially for now\n        const data = await this.model.generate({\n          inputs: chunk.input_features,\n          ...generation_config,\n        });\n\n        // TODO: Right now we only get top beam\n        if (return_timestamps === 'word') {\n          // @ts-expect-error TS2339\n          chunk.tokens = data.sequences.tolist()[0];\n          // @ts-expect-error TS2339\n          chunk.token_timestamps = data.token_timestamps.tolist()[0].map((x: number) => round(x, 2));\n        } else {\n          chunk.tokens = (data as Tensor)[0].tolist();\n        }\n\n        // convert stride to seconds\n        chunk.stride = chunk.stride.map((x) => x / sampling_rate);\n      }\n\n      // Merge text chunks\n      // @ts-ignore\n      const [full_text, optional] = this.tokenizer._decode_asr(chunks, {\n        time_precision,\n        return_timestamps,\n        force_full_sequences,\n      });\n\n      toReturn.push({ text: full_text, ...optional });\n    }\n    return single ? toReturn[0] : toReturn;\n  }\n\n  /**\n   * @type {AutomaticSpeechRecognitionPipelineCallback}\n   * @private\n   */\n  async _call_moonshine(audio: AudioPipelineInputs, kwargs: Partial<AutomaticSpeechRecognitionConfig>) {\n    const single = !Array.isArray(audio);\n    if (single) {\n      audio = [audio as AudioInput];\n    }\n    const sampling_rate = (this.processor as any).feature_extractor.config.sampling_rate;\n    const preparedAudios = await prepareAudios(audio, sampling_rate);\n    const toReturn = [];\n    for (const aud of preparedAudios) {\n      const inputs = await (this.processor as any)(aud);\n\n      // According to the [paper](https://arxiv.org/pdf/2410.15608):\n      // \"We use greedy decoding, with a heuristic limit of 6 output tokens\n      // per second of audio to avoid repeated output sequences.\"\n      const max_new_tokens = Math.floor(aud.length / sampling_rate) * 6;\n      const outputs = await this.model.generate({ max_new_tokens, ...kwargs, ...inputs });\n\n      const text = (this.processor as any).batch_decode(/** @type {Tensor} */ outputs, {\n        skip_special_tokens: true,\n      })[0];\n      toReturn.push({ text });\n    }\n    return single ? toReturn[0] : toReturn;\n  }\n}\n\n/**\n * @typedef {Object} ImageToTextSingle\n * @property {string} generated_text The generated text.\n * @typedef {ImageToTextSingle[]} ImageToTextOutput\n *\n * @callback ImageToTextPipelineCallback Assign labels to the image(s) passed as inputs.\n * @param {ImagePipelineInputs} texts The images to be captioned.\n * @param {Partial<import('./generation/configuration_utils.js').GenerationConfig>} [options] Additional keyword arguments to pass along to the generate method of the model.\n * @returns {Promise<ImageToTextOutput|ImageToTextOutput[]>} An object (or array of objects) containing the generated text(s).\n *\n * @typedef {TextImagePipelineConstructorArgs & ImageToTextPipelineCallback & Disposable} ImageToTextPipelineType\n */\n\n/**\n * Image To Text pipeline using a `AutoModelForVision2Seq`. This pipeline predicts a caption for a given image.\n *\n * **Example:** Generate a caption for an image w/ `Xenova/vit-gpt2-image-captioning`.\n * ```javascript\n * const captioner = await pipeline('image-to-text', 'Xenova/vit-gpt2-image-captioning');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/cats.jpg';\n * const output = await captioner(url);\n * // [{ generated_text: 'a cat laying on a couch with another cat' }]\n * ```\n *\n * **Example:** Optical Character Recognition (OCR) w/ `Xenova/trocr-small-handwritten`.\n * ```javascript\n * const captioner = await pipeline('image-to-text', 'Xenova/trocr-small-handwritten');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/handwriting.jpg';\n * const output = await captioner(url);\n * // [{ generated_text: 'Mr. Brown commented icily.' }]\n * ```\n */\nexport class ImageToTextPipeline\n  extends /** @type {new (options: TextImagePipelineConstructorArgs) => ImageToTextPipelineType} */ Pipeline\n{\n  /**\n   * Create a new ImageToTextPipeline.\n   * @param {TextImagePipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  constructor(options: TextImagePipelineConstructorArgs) {\n    super(options);\n  }\n\n  /** @type {ImageToTextPipelineCallback} */\n  async _call(images: ImagePipelineInputs, generate_kwargs = {}) {\n    const isBatched = Array.isArray(images);\n    const preparedImages = await prepareImages(images);\n\n    const { pixel_values } = await (this.processor as any)(preparedImages);\n\n    const toReturn = [];\n    for (const batch of pixel_values) {\n      batch.dims = [1, ...batch.dims];\n      const output = await (this.model as any).generate({ inputs: batch, ...generate_kwargs });\n      const decoded = (this.tokenizer as any)\n        .batch_decode(/** @type {Tensor} */ output, {\n          skip_special_tokens: true,\n        })\n        .map((x: any) => ({ generated_text: x.trim() }));\n      toReturn.push(decoded);\n    }\n\n    return isBatched ? toReturn : toReturn[0];\n  }\n}\n\n/**\n * @typedef {Object} VocoderOptions\n * @property {PreTrainedModel} [vocoder] The vocoder used by the pipeline (if the model uses one). If not provided, use the default HifiGan vocoder.\n * @typedef {TextAudioPipelineConstructorArgs & VocoderOptions} TextToAudioPipelineConstructorArgs\n */\ntype VocoderOptions = {\n  vocoder: PreTrainedModel | null;\n};\n\n/**\n * @typedef {Object} TextToAudioOutput\n * @property {Float32Array} audio The generated audio waveform.\n * @property {number} sampling_rate The sampling rate of the generated audio waveform.\n *\n * @typedef {Object} TextToAudioPipelineOptions Parameters specific to text-to-audio pipelines.\n * @property {Tensor|Float32Array|string|URL} [speaker_embeddings=null] The speaker embeddings (if the model requires it).\n *\n * @callback TextToAudioPipelineCallback Generates speech/audio from the inputs.\n * @param {string|string[]} texts The text(s) to generate.\n * @param {TextToAudioPipelineOptions} options Parameters passed to the model generation/forward method.\n * @returns {Promise<TextToAudioOutput>} An object containing the generated audio and sampling rate.\n *\n * @typedef {TextToAudioPipelineConstructorArgs & TextToAudioPipelineCallback & Disposable} TextToAudioPipelineType\n */\n\ntype TextToAudioPipelineConstructorArgs = TextAudioPipelineConstructorArgs & VocoderOptions;\n\n/**\n * Text-to-audio generation pipeline using any `AutoModelForTextToWaveform` or `AutoModelForTextToSpectrogram`.\n * This pipeline generates an audio file from an input text and optional other conditional inputs.\n *\n * **Example:** Generate audio from text with `Xenova/speecht5_tts`.\n * ```javascript\n * const synthesizer = await pipeline('text-to-speech', 'Xenova/speecht5_tts', { quantized: false });\n * const speaker_embeddings = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/speaker_embeddings.bin';\n * const out = await synthesizer('Hello, my dog is cute', { speaker_embeddings });\n * // {\n * //   audio: Float32Array(26112) [-0.00005657337896991521, 0.00020583874720614403, ...],\n * //   sampling_rate: 16000\n * // }\n * ```\n *\n * You can then save the audio to a .wav file with the `wavefile` package:\n * ```javascript\n * import wavefile from 'wavefile';\n * import fs from 'fs';\n *\n * const wav = new wavefile.WaveFile();\n * wav.fromScratch(1, out.sampling_rate, '32f', out.audio);\n * fs.writeFileSync('out.wav', wav.toBuffer());\n * ```\n *\n * **Example:** Multilingual speech generation with `Xenova/mms-tts-fra`. See [here](https://huggingface.co/models?pipeline_tag=text-to-speech&other=vits&sort=trending) for the full list of available languages (1107).\n * ```javascript\n * const synthesizer = await pipeline('text-to-speech', 'Xenova/mms-tts-fra');\n * const out = await synthesizer('Bonjour');\n * // {\n * //   audio: Float32Array(23808) [-0.00037693005288019776, 0.0003325853613205254, ...],\n * //   sampling_rate: 16000\n * // }\n * ```\n */\nexport class TextToAudioPipeline\n  extends /** @type {new (options: TextToAudioPipelineConstructorArgs) => TextToAudioPipelineType} */ Pipeline\n{\n  DEFAULT_VOCODER_ID = 'Xenova/speecht5_hifigan';\n\n  /**\n   * Create a new TextToAudioPipeline.\n   * @param {TextToAudioPipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  vocoder: PreTrainedModel | null;\n  constructor(options: TextToAudioPipelineConstructorArgs) {\n    super(options);\n\n    // TODO: Find a better way for `pipeline` to set the default vocoder\n    this.vocoder = options.vocoder ?? null;\n  }\n\n  /** @type {TextToAudioPipelineCallback} */\n  async _call(\n    text_inputs: string | string[],\n    { speaker_embeddings = null }: { speaker_embeddings: Tensor | Float32Array | string | URL | null },\n  ) {\n    // console.log(\"inside call\", this.model.config);\n    // If this.processor is not set, we are using a `AutoModelForTextToWaveform` model\n    if (this.processor) {\n      // console.log(\"Found processor:\", this.processor)\n      return this._call_text_to_spectrogram(text_inputs, { speaker_embeddings });\n    } else {\n      console.log(\"No Processor found, running waveform\")\n      return this._call_text_to_waveform(text_inputs);\n    }\n  }\n\n  async _call_text_to_waveform(text_inputs: string | string[]) {\n    // Run tokenization\n    const inputs = (this.tokenizer as any)(text_inputs, {\n      padding: true,\n      truncation: true,\n    });\n\n    // Generate waveform\n    const { waveform } = await (this.model as any)(inputs);\n\n    // @ts-expect-error TS2339\n    const sampling_rate = this.model.config.sampling_rate;\n    return new RawAudio(\n      waveform.data,\n      sampling_rate,\n    );\n  }\n\n  async _call_text_to_spectrogram(\n    text_inputs: string | string[],\n    { speaker_embeddings = null as Tensor | Float32Array | string | URL | null },\n  ) {\n    // Load vocoder, if not provided\n    if (!this.vocoder) {\n      console.log('No vocoder specified, using default HifiGan vocoder.');\n      this.vocoder = await (AutoModel as any).from_pretrained(this.DEFAULT_VOCODER_ID, { dtype: 'fp32' });\n    }\n\n    // Load speaker embeddings as Float32Array from path/URL\n    if (typeof speaker_embeddings === 'string' || speaker_embeddings instanceof URL) {\n      // Load from URL with fetch\n      speaker_embeddings = new Float32Array(await (await fetch(speaker_embeddings)).arrayBuffer());\n    }\n\n    if (speaker_embeddings instanceof Float32Array) {\n      speaker_embeddings = new Tensor('float32', speaker_embeddings, [1, speaker_embeddings.length]);\n    } else if (!(speaker_embeddings instanceof Tensor)) {\n      throw new Error('Speaker embeddings must be a `Tensor`, `Float32Array`, `string`, or `URL`.');\n    }\n\n    // Run tokenization\n    const { input_ids } = (this.tokenizer as any)(text_inputs, {\n      padding: true,\n      truncation: true,\n    });\n\n    // NOTE: At this point, we are guaranteed that `speaker_embeddings` is a `Tensor`\n    // @ts-ignore\n    const { waveform } = await (this.model as any).generate_speech(input_ids, speaker_embeddings, {\n      vocoder: this.vocoder,\n    });\n\n    const sampling_rate = (this.processor as any).feature_extractor.config.sampling_rate;\n    return new RawAudio(\n        waveform.data,\n        sampling_rate,\n    );\n  }\n}\n\n/**\n * @callback ImageToImagePipelineCallback Transform the image(s) passed as inputs.\n * @param {ImagePipelineInputs} images The images to transform.\n * @returns {Promise<RawImage|RawImage[]>} The transformed image or list of images.\n *\n * @typedef {ImagePipelineConstructorArgs & ImageToImagePipelineCallback & Disposable} ImageToImagePipelineType\n */\n\n/**\n * Image to Image pipeline using any `AutoModelForImageToImage`. This pipeline generates an image based on a previous image input.\n *\n * **Example:** Super-resolution w/ `Xenova/swin2SR-classical-sr-x2-64`\n * ```javascript\n * const upscaler = await pipeline('image-to-image', 'Xenova/swin2SR-classical-sr-x2-64');\n * const url = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/butterfly.jpg';\n * const output = await upscaler(url);\n * // RawImage {\n * //   data: Uint8Array(786432) [ 41, 31, 24,  43, ... ],\n * //   width: 512,\n * //   height: 512,\n * //   channels: 3\n * // }\n * ```\n */\nexport class ImageToImagePipeline\n  extends /** @type {new (options: ImagePipelineConstructorArgs) => ImageToImagePipelineType} */ Pipeline\n{\n  /**\n   * Create a new ImageToImagePipeline.\n   * @param {ImagePipelineConstructorArgs} options An object used to instantiate the pipeline.\n   */\n  processor: any;\n\n  constructor(options: ImagePipelineConstructorArgs) {\n    super(options);\n    this.processor = options.processor;\n  }\n\n  /** @type {ImageToImagePipelineCallback} */\n  async _call(images: ImagePipelineInputs) {\n    const preparedImages = await prepareImages(images);\n    const inputs = await this.processor(preparedImages);\n    const outputs = await (this.model as any)(inputs);\n\n    /** @type {RawImage[]} */\n    const toReturn = [];\n    for (const batch of outputs.reconstruction) {\n      const output = batch.squeeze().clamp_(0, 1).mul_(255).round_().to('uint8');\n      toReturn.push(RawImage.fromTensor(output));\n    }\n\n    return toReturn.length > 1 ? toReturn : toReturn[0];\n  }\n}\n\nexport const SUPPORTED_TASKS = {\n  'text-generation': {\n    tokenizer: AutoTokenizer,\n    pipeline: TextGenerationPipeline,\n    model: AutoModelForCausalLM,\n    default: {\n      // TODO: replace with original\n      // \"model\": \"gpt2\",\n      model: 'Xenova/gpt2',\n    },\n    type: 'text',\n  },\n  'automatic-speech-recognition': {\n    tokenizer: AutoTokenizer,\n    pipeline: AutomaticSpeechRecognitionPipeline,\n    model: [AutoModelForSpeechSeq2Seq, AutoModelForCTC],\n    processor: AutoProcessor,\n    default: {\n      // TODO: replace with original\n      // \"model\": \"openai/whisper-tiny.en\",\n      model: 'Xenova/whisper-tiny.en',\n    },\n    type: 'multimodal',\n  },\n  'text-to-audio': {\n    tokenizer: AutoTokenizer,\n    pipeline: TextToAudioPipeline,\n    model: [AutoModelForTextToWaveform, AutoModelForTextToSpectrogram],\n    processor: [AutoProcessor, /* Some don't use a processor */ null],\n    default: {\n      // TODO: replace with original\n      // \"model\": \"microsoft/speecht5_tts\",\n      model: 'Xenova/speecht5_tts',\n    },\n    type: 'text',\n  },\n  'image-to-text': {\n    tokenizer: AutoTokenizer,\n    pipeline: ImageToTextPipeline,\n    model: AutoModelForVision2Seq,\n    processor: AutoProcessor,\n    default: {\n      // TODO: replace with original\n      // \"model\": \"nlpconnect/vit-gpt2-image-captioning\",\n      model: 'Xenova/vit-gpt2-image-captioning',\n    },\n    type: 'multimodal',\n  },\n  'image-to-image': {\n    // no tokenizer\n    pipeline: ImageToImagePipeline,\n    model: AutoModelForImageToImage,\n    processor: AutoProcessor,\n    default: {\n      // TODO: replace with original\n      // \"model\": \"caidas/swin2SR-classical-sr-x2-64\",\n      model: 'Xenova/swin2SR-classical-sr-x2-64',\n    },\n    type: 'image',\n  },\n\n  // This task serves as a useful interface for dealing with sentence-transformers (https://huggingface.co/sentence-transformers).\n  'feature-extraction': {\n    tokenizer: AutoTokenizer,\n    pipeline: FeatureExtractionPipeline,\n    model: AutoModel,\n    default: {\n      // TODO: replace with original\n      // \"model\": \"sentence-transformers/all-MiniLM-L6-v2\",\n      model: 'Xenova/all-MiniLM-L6-v2',\n    },\n    type: 'text',\n  },\n  'image-feature-extraction': {\n    processor: AutoProcessor,\n    pipeline: ImageFeatureExtractionPipeline,\n    model: [AutoModelForImageFeatureExtraction, AutoModel],\n    default: {\n      // TODO: replace with original\n      // \"model\": \"google/vit-base-patch16-224\",\n      model: 'Xenova/vit-base-patch16-224-in21k',\n    },\n    type: 'image',\n  },\n} as const;\n\n// TODO: Add types for TASK_ALIASES\nexport const TASK_ALIASES = {\n  asr: 'automatic-speech-recognition',\n  'text-to-speech': 'text-to-audio',\n\n  // Add for backwards compatibility\n  embeddings: 'feature-extraction',\n} as const;\n\n/**\n * @typedef {keyof typeof SUPPORTED_TASKS} TaskType\n * @typedef {keyof typeof TASK_ALIASES} AliasType\n * @typedef {TaskType | AliasType} PipelineType All possible pipeline types.\n * @typedef {{[K in TaskType]: InstanceType<typeof SUPPORTED_TASKS[K][\"pipeline\"]>}} SupportedTasks A mapping of pipeline names to their corresponding pipeline classes.\n * @typedef {{[K in AliasType]: InstanceType<typeof SUPPORTED_TASKS[TASK_ALIASES[K]][\"pipeline\"]>}} AliasTasks A mapping from pipeline aliases to their corresponding pipeline classes.\n * @typedef {SupportedTasks & AliasTasks} AllTasks A mapping from all pipeline names and aliases to their corresponding pipeline classes.\n */\n\n/**\n * Utility factory method to build a `Pipeline` object.\n *\n * @template {PipelineType} T The type of pipeline to return.\n * @param {T} task The task defining which pipeline will be returned. Currently accepted tasks are:\n *  - `\"automatic-speech-recognition\"`: will return a `AutomaticSpeechRecognitionPipeline`.\n *  - `\"feature-extraction\"`: will return a `FeatureExtractionPipeline`.\n *  - `\"image-to-text\"`: will return a `ImageToTextPipeline`.\n *  - `\"text-generation\"`: will return a `TextGenerationPipeline`.\n * @param {string} [model=null] The name of the pre-trained model to use. If not specified, the default model for the task will be used.\n * @param {import('./utils/hub.js').PretrainedModelOptions} [options] Optional parameters for the pipeline.\n * @returns {Promise<AllTasks[T]>} A Pipeline object for the specified task.\n * @throws {Error} If an unsupported pipeline is requested.\n */\nexport async function pipeline(\n  task: PipelineType,\n  model: string | null = null,\n  {\n    progress_callback = null,\n    config = null,\n    cache_dir = null,\n    local_files_only = false,\n    revision = 'main',\n    device = null,\n    dtype = null,\n    model_file_name = null,\n    session_options = {},\n  } = {},\n) {\n  // Helper method to construct pipeline\n\n  // Apply aliases\n  // @ts-ignore\n  task = TASK_ALIASES[task] ?? task;\n\n  // Get pipeline info\n  const pipelineInfo = SUPPORTED_TASKS[task.split('_', 1)[0] as keyof typeof SUPPORTED_TASKS];\n  if (!pipelineInfo) {\n    throw Error(`Unsupported pipeline: ${task}. Must be one of [${Object.keys(SUPPORTED_TASKS)}]`);\n  }\n\n  // Use model if specified, otherwise, use default\n  if (!model) {\n    model = pipelineInfo.default.model;\n    console.log(`No model specified. Using default model: \"${model}\".`);\n  }\n\n  const pretrainedOptions = {\n    progress_callback,\n    config,\n    cache_dir,\n    local_files_only,\n    revision,\n    device,\n    dtype,\n    model_file_name,\n    session_options,\n  };\n\n  const classes = new Map([\n    ['tokenizer', (pipelineInfo as any).tokenizer],\n    ['model', (pipelineInfo as any).model],\n    ['processor', (pipelineInfo as any).processor],\n  ]);\n\n  // Load model, tokenizer, and processor (if they exist)\n  const results = await loadItems(classes, model, pretrainedOptions);\n  results.task = task;\n\n  dispatchCallback(progress_callback, {\n    status: 'ready',\n    task: task,\n    model: model,\n  });\n\n  const pipelineClass = pipelineInfo.pipeline;\n  return new pipelineClass(results);\n}\n\n/**\n * Helper function to get applicable model, tokenizer, or processor classes for a given model.\n * @param {Map<string, any>} mapping The mapping of names to classes, arrays of classes, or null.\n * @param {string} model The name of the model to load.\n * @param {import('./utils/hub.js').PretrainedOptions} pretrainedOptions The options to pass to the `from_pretrained` method.\n * @private\n */\nasync function loadItems(mapping: Map<string, any>, model: string, pretrainedOptions: PretrainedOptions) {\n  const result = Object.create(null);\n\n  /**@type {Promise[]} */\n  const promises = [];\n  for (const [name, cls] of mapping.entries()) {\n    if (!cls) continue;\n\n    /**@type {Promise} */\n    let promise;\n    if (Array.isArray(cls)) {\n      promise = new Promise(async (resolve, reject) => {\n        let e;\n        for (const c of cls) {\n          if (c === null) {\n            // If null, we resolve it immediately, meaning the relevant\n            // class was not found, but it is optional.\n            resolve(null);\n            return;\n          }\n          try {\n            resolve(await c.from_pretrained(model, pretrainedOptions));\n            return;\n          } catch (err) {\n            if ((err as Error).message?.includes('Unsupported model type')) {\n              // If the error is due to an unsupported model type, we\n              // save the error and try the next class.\n              e = err as Error;\n            } else if ((err as Error).message?.includes('Could not locate file')) {\n              e = err as Error;\n            } else {\n              reject(err);\n              return;\n            }\n          }\n        }\n        reject(e);\n      });\n    } else {\n      promise = cls.from_pretrained(model, pretrainedOptions);\n    }\n\n    result[name] = promise;\n    promises.push(promise);\n  }\n\n  // Wait for all promises to resolve (in parallel)\n  await Promise.all(promises);\n\n  // Then assign to result\n  for (const [name, promise] of Object.entries(result)) {\n    result[name] = await promise;\n  }\n\n  return result;\n}\n\nfunction isChat(obj: any): obj is Chat {\n  return Array.isArray(obj) && obj.every((x) => typeof x === 'object' && 'role' in x && 'content' in x);\n}\n","/**\n * @module generation/streamers\n */\n\nimport { mergeArrays } from '../utils/core.js';\nimport { is_chinese_char, PreTrainedTokenizer } from '../tokenizers.js';\nimport { apis } from '../env.js';\n\nexport class BaseStreamer {\n  /**\n   * Function that is called by `.generate()` to push new tokens\n   * @param {bigint[][]} value\n   */\n  put(value: bigint[][]) {\n    throw Error('Not implemented');\n  }\n\n  /**\n   * Function that is called by `.generate()` to signal the end of generation\n   */\n  end() {\n    throw Error('Not implemented');\n  }\n}\n\nconst stdout_write = apis.IS_PROCESS_AVAILABLE ? (x: string) => process.stdout.write(x) : (x: string) => console.log(x);\n\n/**\n * Simple text streamer that prints the token(s) to stdout as soon as entire words are formed.\n */\nexport class TextStreamer extends BaseStreamer {\n  /**\n   *\n   * @param {import('../tokenizers.js').PreTrainedTokenizer} tokenizer\n   * @param {Object} options\n   * @param {boolean} [options.skip_prompt=false] Whether to skip the prompt tokens\n   * @param {function(string): void} [options.callback_function=null] Function to call when a piece of text is ready to display\n   * @param {function(bigint[]): void} [options.token_callback_function=null] Function to call when a new token is generated\n   * @param {Object} [options.decode_kwargs={}] Additional keyword arguments to pass to the tokenizer's decode method\n   */\n\n  tokenizer: PreTrainedTokenizer;\n  skip_prompt: boolean;\n  callback_function: (x: string) => void;\n  token_callback_function: any;\n  decode_kwargs: any;\n  print_len: number;\n  next_tokens_are_prompt: boolean;\n  token_cache: bigint[];\n\n  constructor(\n    tokenizer: PreTrainedTokenizer,\n    {\n      skip_prompt = false,\n      callback_function = null,\n      token_callback_function = null,\n      skip_special_tokens = true,\n      decode_kwargs = {},\n      ...kwargs\n    } = {},\n  ) {\n    super();\n    this.tokenizer = tokenizer;\n    this.skip_prompt = skip_prompt;\n    this.callback_function = callback_function ?? stdout_write;\n    this.token_callback_function = token_callback_function;\n    this.decode_kwargs = { skip_special_tokens, ...decode_kwargs, ...kwargs };\n\n\n    // variables used in the streaming process\n    this.token_cache = [];\n    this.print_len = 0;\n    this.next_tokens_are_prompt = true;\n  }\n\n  /**\n   * Receives tokens, decodes them, and prints them to stdout as soon as they form entire words.\n   * @param {bigint[][]} value\n   */\n  put(value: bigint[][]) {\n    if (value.length > 1) {\n      throw Error('TextStreamer only supports batch size of 1');\n    }\n\n    if (this.skip_prompt && this.next_tokens_are_prompt) {\n      this.next_tokens_are_prompt = false;\n      return;\n    }\n\n    const tokens = value[0];\n    this.token_callback_function?.(tokens);\n\n    // Add the new token to the cache and decodes the entire thing.\n    this.token_cache = mergeArrays(this.token_cache, tokens);\n    const text = this.tokenizer.decode(this.token_cache, this.decode_kwargs);\n\n    let printable_text;\n    if (text.endsWith('\\n')) {\n      // After the symbol for a new line, we flush the cache.\n      printable_text = text.slice(this.print_len);\n      this.token_cache = [];\n      this.print_len = 0;\n    } else if (text.length > 0 && is_chinese_char(text.charCodeAt(text.length - 1))) {\n      // If the last token is a CJK character, we print the characters.\n      printable_text = text.slice(this.print_len);\n      this.print_len += printable_text.length;\n    } else {\n      // Otherwise, prints until the last space char (simple heuristic to avoid printing incomplete words,\n      // which may change with the subsequent token -- there are probably smarter ways to do this!)\n      printable_text = text.slice(this.print_len, text.lastIndexOf(' ') + 1);\n      this.print_len += printable_text.length;\n    }\n\n    this.on_finalized_text(printable_text, false);\n  }\n\n  /**\n   * Flushes any remaining cache and prints a newline to stdout.\n   */\n  end() {\n    let printable_text;\n    if (this.token_cache.length > 0) {\n      const text = this.tokenizer.decode(this.token_cache, this.decode_kwargs);\n      printable_text = text.slice(this.print_len);\n      this.token_cache = [];\n      this.print_len = 0;\n    } else {\n      printable_text = '';\n    }\n    this.next_tokens_are_prompt = true;\n    this.on_finalized_text(printable_text, true);\n  }\n\n  /**\n   * Prints the new text to stdout. If the stream is ending, also prints a newline.\n   * @param {string} text\n   * @param {boolean} stream_end\n   */\n  on_finalized_text(text: string, stream_end: boolean) {\n    if (text.length > 0) {\n      this.callback_function?.(text);\n    }\n    if (stream_end && this.callback_function === stdout_write && apis.IS_PROCESS_AVAILABLE) {\n      this.callback_function?.('\\n');\n    }\n  }\n}\n\n/**\n * Utility class to handle streaming of tokens generated by whisper speech-to-text models.\n * Callback functions are invoked when each of the following events occur:\n *  - A new chunk starts (on_chunk_start)\n *  - A new token is generated (callback_function)\n *  - A chunk ends (on_chunk_end)\n *  - The stream is finalized (on_finalize)\n */\nexport class WhisperTextStreamer extends TextStreamer {\n  /**\n   * @param {import('../tokenizers.js').WhisperTokenizer} tokenizer\n   * @param {Object} options\n   * @param {boolean} [options.skip_prompt=false] Whether to skip the prompt tokens\n   * @param {function(string): void} [options.callback_function=null] Function to call when a piece of text is ready to display\n   * @param {function(bigint[]): void} [options.token_callback_function=null] Function to call when a new token is generated\n   * @param {function(number): void} [options.on_chunk_start=null] Function to call when a new chunk starts\n   * @param {function(number): void} [options.on_chunk_end=null] Function to call when a chunk ends\n   * @param {function(): void} [options.on_finalize=null] Function to call when the stream is finalized\n   * @param {number} [options.time_precision=0.02] Precision of the timestamps\n   * @param {boolean} [options.skip_special_tokens=true] Whether to skip special tokens when decoding\n   * @param {Object} [options.decode_kwargs={}] Additional keyword arguments to pass to the tokenizer's decode method\n   */\n  timestamp_begin: number;\n  time_precision: number;\n  waiting_for_timestamp: boolean;\n\n  constructor(\n    tokenizer: PreTrainedTokenizer,\n    {\n      skip_prompt = false,\n      callback_function = null,\n      token_callback_function = null,\n      on_chunk_start = null,\n      on_chunk_end = null,\n      on_finalize = null,\n      time_precision = 0.02,\n      skip_special_tokens = true,\n      decode_kwargs = {},\n    } = {},\n  ) {\n    super(tokenizer, {\n      skip_prompt,\n      skip_special_tokens,\n      callback_function,\n      token_callback_function,\n      decode_kwargs,\n    });\n    this.timestamp_begin = tokenizer.timestamp_begin;\n\n    this.on_chunk_start = on_chunk_start;\n    this.on_chunk_end = on_chunk_end;\n    this.on_finalize = on_finalize;\n\n    this.time_precision = time_precision;\n\n    this.waiting_for_timestamp = false;\n  }\n\n  /**\n   * @param {bigint[][]} value\n   */\n  put(value: bigint[][]) {\n    if (value.length > 1) {\n      throw Error('WhisperTextStreamer only supports batch size of 1');\n    }\n    const tokens = value[0];\n\n    // Check if the token is a timestamp\n    if (tokens.length === 1) {\n      const offset = Number(tokens[0]) - this.timestamp_begin;\n      if (offset >= 0) {\n        const time = offset * this.time_precision;\n        if (this.waiting_for_timestamp) {\n          this.on_chunk_end?.(time);\n        } else {\n          this.on_chunk_start?.(time);\n        }\n        this.waiting_for_timestamp = !this.waiting_for_timestamp; // Toggle\n        value = [[]]; // Skip timestamp\n      }\n    }\n    return super.put(value);\n  }\n\n  end() {\n    super.end();\n    this.on_finalize?.();\n  }\n}\n","// Some of this code is from https://github.com/hexgrad/kokoro/\nimport { phonemize as espeakng } from \"phonemizer\";\n\n  /**\n   * Helper function to split a string on a regex, but keep the delimiters.\n   * This is required, because the JavaScript `.split()` method does not keep the delimiters,\n   * and wrapping in a capturing group causes issues with existing capturing groups (due to nesting).\n   * @param {string} text The text to split.\n   * @param {RegExp} regex The regex to split on.\n   * @returns {{match: boolean; text: string}[]} The split string.\n   */\n  function split(text: string, regex: RegExp) {\n    const result = [];\n    let prev = 0;\n    for (const match of text.matchAll(regex)) {\n      const fullMatch = match[0];\n      if (prev < match.index) {\n        result.push({ match: false, text: text.slice(prev, match.index) });\n      }\n      if (fullMatch.length > 0) {\n        result.push({ match: true, text: fullMatch });\n      }\n      prev = match.index + fullMatch.length;\n    }\n    if (prev < text.length) {\n      result.push({ match: false, text: text.slice(prev) });\n    }\n    return result;\n  }\n\n  /**\n   * Helper function to split numbers into phonetic equivalents\n   * @param {string} match The matched number\n   * @returns {string} The phonetic equivalent\n   */\n  function split_num(match: string) {\n    if (match.includes(\".\")) {\n      return match;\n    } else if (match.includes(\":\")) {\n      let [h, m] = match.split(\":\").map(Number);\n      if (m === 0) {\n        return `${h} o'clock`;\n      } else if (m < 10) {\n        return `${h} oh ${m}`;\n      }\n      return `${h} ${m}`;\n    }\n    let year = parseInt(match.slice(0, 4), 10);\n    if (year < 1100 || year % 1000 < 10) {\n      return match;\n    }\n    let left = match.slice(0, 2);\n    let right = parseInt(match.slice(2, 4), 10);\n    let suffix = match.endsWith(\"s\") ? \"s\" : \"\";\n    if (year % 1000 >= 100 && year % 1000 <= 999) {\n      if (right === 0) {\n        return `${left} hundred${suffix}`;\n      } else if (right < 10) {\n        return `${left} oh ${right}${suffix}`;\n      }\n    }\n    return `${left} ${right}${suffix}`;\n  }\n\n  /**\n   * Helper function to format monetary values\n   * @param {string} match The matched currency\n   * @returns {string} The formatted currency\n   */\n  function flip_money(match: string) {\n    const bill = match[0] === \"$\" ? \"dollar\" : \"pound\";\n    if (isNaN(Number(match.slice(1)))) {\n      return `${match.slice(1)} ${bill}s`;\n    } else if (!match.includes(\".\")) {\n      let suffix = match.slice(1) === \"1\" ? \"\" : \"s\";\n      return `${match.slice(1)} ${bill}${suffix}`;\n    }\n    const [b, c] = match.slice(1).split(\".\");\n    const d = parseInt(c.padEnd(2, \"0\"), 10);\n    let coins = match[0] === \"$\" ? (d === 1 ? \"cent\" : \"cents\") : d === 1 ? \"penny\" : \"pence\";\n    return `${b} ${bill}${b === \"1\" ? \"\" : \"s\"} and ${d} ${coins}`;\n  }\n\n  /**\n   * Helper function to process decimal numbers\n   * @param {string} match The matched number\n   * @returns {string} The formatted number\n   */\n  function point_num(match: string) {\n    let [a, b] = match.split(\".\");\n    return `${a} point ${b.split(\"\").join(\" \")}`;\n  }\n\n  /**\n   * Normalize text for phonemization\n   * @param {string} text The text to normalize\n   * @returns {string} The normalized text\n   */\n  function normalize_text(text: string) {\n    return (\n      text\n        // 1. Handle quotes and brackets\n        .replace(/[‘’]/g, \"'\")\n        .replace(/«/g, \"“\")\n        .replace(/»/g, \"”\")\n        .replace(/[“”]/g, '\"')\n        .replace(/\\(/g, \"«\")\n        .replace(/\\)/g, \"»\")\n\n        // 2. Replace uncommon punctuation marks\n        .replace(/、/g, \", \")\n        .replace(/。/g, \". \")\n        .replace(/！/g, \"! \")\n        .replace(/，/g, \", \")\n        .replace(/：/g, \": \")\n        .replace(/；/g, \"; \")\n        .replace(/？/g, \"? \")\n\n        // 3. Whitespace normalization\n        .replace(/[^\\S \\n]/g, \" \")\n        .replace(/  +/, \" \")\n        .replace(/(?<=\\n) +(?=\\n)/g, \"\")\n\n        // 4. Abbreviations\n        .replace(/\\bD[Rr]\\.(?= [A-Z])/g, \"Doctor\")\n        .replace(/\\b(?:Mr\\.|MR\\.(?= [A-Z]))/g, \"Mister\")\n        .replace(/\\b(?:Ms\\.|MS\\.(?= [A-Z]))/g, \"Miss\")\n        .replace(/\\b(?:Mrs\\.|MRS\\.(?= [A-Z]))/g, \"Mrs\")\n        .replace(/\\betc\\.(?! [A-Z])/gi, \"etc\")\n\n        // 5. Normalize casual words\n        .replace(/\\b(y)eah?\\b/gi, \"$1e'a\")\n\n        // 5. Handle numbers and currencies\n        .replace(/\\d*\\.\\d+|\\b\\d{4}s?\\b|(?<!:)\\b(?:[1-9]|1[0-2]):[0-5]\\d\\b(?!:)/g, split_num)\n        .replace(/(?<=\\d),(?=\\d)/g, \"\")\n        .replace(/[$£]\\d+(?:\\.\\d+)?(?: hundred| thousand| (?:[bm]|tr)illion)*\\b|[$£]\\d+\\.\\d\\d?\\b/gi, flip_money)\n        .replace(/\\d*\\.\\d+/g, point_num)\n        .replace(/(?<=\\d)-(?=\\d)/g, \" to \")\n        .replace(/(?<=\\d)S/g, \" S\")\n\n        // 6. Handle possessives\n        .replace(/(?<=[BCDFGHJ-NP-TV-Z])'?s\\b/g, \"'S\")\n        .replace(/(?<=X')S\\b/g, \"s\")\n\n        // 7. Handle hyphenated words/letters\n        .replace(/(?:[A-Za-z]\\.){2,} [a-z]/g, (m) => m.replace(/\\./g, \"-\"))\n        .replace(/(?<=[A-Z])\\.(?=[A-Z])/gi, \"-\")\n\n        // 8. Strip leading and trailing whitespace\n        .trim()\n    );\n  }\n\n  /**\n   * Escapes regular expression special characters from a string by replacing them with their escaped counterparts.\n   *\n   * @param {string} string The string to escape.\n   * @returns {string} The escaped string.\n   */\n  function escapeRegExp(string: string) {\n    return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"); // $& means the whole matched string\n  }\n\n  const PUNCTUATION = ';:,.!?¡¿—…\"«»“”(){}[]';\n  const PUNCTUATION_PATTERN = new RegExp(`(\\\\s*[${escapeRegExp(PUNCTUATION)}]+\\\\s*)+`, \"g\");\n\n  const HINDI_PHONEME_MAP: { [key: string]: string } = {\n    // Vowels - Updated to be more accurate and broadly understood\n    'अ': 'a',      // a\n    'आ': 'aː',     // Long 'a'\n    'इ': 'e',      // Lax 'i'\n    'ई': 'eː',     // Long 'i'\n    'उ': 'ʊ',      // Lax 'u'\n    'ऊ': 'uː',     // Long 'u'\n    'ऋ': 'ri',    // 'ri' sound (often pronounced like this) -  Could also be ɾɪ\n    'ए': 'eː',     // Long 'e'\n    'ऐ': 'ɛ',      // Diphthong/Monophthong 'ai' - More accurately [ɛ] or [æ] in many dialects\n    'ओ': 'oː',     // Long 'o'\n    'औ': 'ɔ',      // Diphthong/Monophthong 'au' - More accurately [ɔ] or [ɒ] in many dialects\n    'ऍ': 'æ',      // Open 'e' sound (like in 'cat') - Borrowed sound\n    'ऑ': 'ɒ',      // Open 'o' sound (like in 'caught') - Borrowed sound\n\n    // Consonants - Updated for broader IPA understanding (using alveolar series where applicable)\n    'क': 'k',      // Voiceless velar stop\n    'ख': 'kʰ',     // Aspirated voiceless velar stop\n    'ग': 'g',      // Voiced velar stop\n    'घ': 'gʰ',     // Aspirated voiced velar stop\n    'ङ': 'ŋ',      // Velar nasal\n    'च': 'tʃ',     // Voiceless postalveolar affricate\n    'छ': 'tʃʰ',    // Aspirated voiceless postalveolar affricate\n    'ज': 'dʒ',     // Voiced postalveolar affricate\n    'झ': 'dʒʰ',    // Aspirated voiced postalveolar affricate\n    'ञ': 'ɲ',      // Palatal nasal\n    'ट': 'ʈ',      // Voiceless retroflex stop\n    'ठ': 'ʈʰ',     // Aspirated voiceless retroflex stop\n    'ड': 'ɖ',      // Voiced retroflex stop\n    'ढ': 'ɖʰ',     // Aspirated voiced retroflex stop\n    'ण': 'ɳ',      // Retroflex nasal\n    'त': 't',      // Voiceless alveolar stop (Technically dental [t̪])\n    'थ': 'tʰ',     // Aspirated voiceless alveolar stop (Technically dental [t̪ʰ])\n    'द': 'd',      // Voiced alveolar stop (Technically dental [d̪])\n    'ध': 'dʰ',     // Aspirated voiced alveolar stop (Technically dental [d̪ʰ])\n    'न': 'n',      // Alveolar nasal (Technically dental [n̪])\n    'प': 'p',      // Voiceless bilabial stop\n    'फ': 'pʰ',     // Aspirated voiceless bilabial stop\n    'ब': 'b',      // Voiced bilabial stop\n    'भ': 'bʰ',     // Aspirated voiced bilabial stop\n    'म': 'm',      // Bilabial nasal\n    'य': 'j',      // Palatal approximant\n    'र': 'r',      // Alveolar trill or flap\n    'ल': 'l',      // Alveolar lateral approximant\n    'व': 'w',      // Bilabial approximant (More common pronunciation, technically could be labiodental [ʋ])\n    'श': 'ʃ',      // Postalveolar voiceless fricative (Often used, but 'ष' is retroflex [ʂ])\n    'ष': 'ʂ',      // Retroflex voiceless fricative (More accurate for 'ष')\n    'स': 's',      // Alveolar voiceless fricative (Technically dental [s̪])\n    'ह': 'h',      // Voiceless glottal fricative (Simpler and common, could be breathy voiced [ɦ])\n\n    // Matras (Vowel Marks) - Updated to match vowel changes\n    'ा': 'aː',     // aa matra\n    'ि': 'ɪ',      // i matra\n    'ी': 'iː',     // ee matra\n    'ु': 'ʊ',      // u matra\n    'ू': 'uː',     // oo matra\n    'ृ': 'ri',    // ri matra - Could also be ɾɪ\n    'े': 'eː',     // e matra\n    'ै': 'ɛ',      // ai matra\n    'ो': 'oː',     // o matra\n    'ौ': 'ɔ',      // au matra\n    'ं': 'n',      // Anusvara - Simplified to 'n' for general nasal consonant (See notes below)\n    'ः': 'h',      // Visarga\n    '्': '',       // Halant/Virama - Removes inherent vowel\n\n    // Nukta variations - Generally correct\n    'क़': 'q',      // Uvular stop\n    'ख़': 'x',      // Voiceless velar fricative\n    'ग़': 'ɣ',      // Voiced velar fricative\n    'ज़': 'z',      // Voiced alveolar fricative\n    'ड़': 'ɽ',      // Retroflex flap\n    'ढ़': 'ɽʰ',     // Aspirated retroflex flap\n    'फ़': 'f',      // Labiodental fricative\n  };\n\n  // Add function to detect script\n  // function isDevanagari(text: string): boolean {\n  //   return /[\\u0900-\\u097F]/.test(text);\n  // }\n\n  // Add Spanish phoneme detection\n  // function isSpanish(text: string): boolean {\n  //   return /[áéíóúñ¿¡]|ll|ñ/i.test(text);\n  // }\n\n  // Add Spanish phoneme mappings\n  const SPANISH_PHONEME_MAP: { [key: string]: string } = {\n    // Vowels\n    'a': 'a',\n    'á': 'ˈa',\n    'e': 'e',\n    'é': 'ˈe',\n    'i': 'i',\n    'í': 'ˈi',\n    'o': 'o',\n    'ó': 'ˈo',\n    'u': 'u',\n    'ú': 'ˈu',\n    'ü': 'u',\n\n    // Consonants\n    'b': 'b',\n    'v': 'β',\n    'c': 'k',\n    'ch': 'tʃ',\n    'd': 'ð',\n    'f': 'f',\n    'g': 'ɡ',\n    'h': '',  // silent in Spanish\n    'j': 'x',\n    'k': 'k',\n    'l': 'l',\n    'll': 'j',\n    'm': 'm',\n    'n': 'n',\n    'ñ': 'ɲ',\n    'p': 'p',\n    'q': 'k',\n    'r': 'ɾ',\n    'rr': 'r',\n    's': 's',\n    't': 't',\n    'w': 'w',\n    'x': 'ks',\n    'y': 'ʝ',\n    'z': 'θ'  // for European Spanish\n  };\n\n  function isHinglish(text: string): boolean {\n    // Common Hinglish words and patterns\n    const hinglishPatterns = [\n      /\\b(aap|tum|hum|main|mein|ham|yeh|woh|kya|kaun|kaise|kyun|kab|kahan|yahan|wahan)\\b/i,\n      /\\b(hai|hain|ho|hoga|tha|the|thi|thin|raha|rahe|rahi|rahin)\\b/i, // Common verb forms\n      /\\b(ka|ke|ki|ko|se|par|me|mein|pe)\\b/i, // Common postpositions\n      /\\b(accha|theek|bahut|bohot|thoda|zyada|kam|jyada)\\b/i, // Common adjectives and adverbs\n      /\\b(karo|karta|karti|karta|karo|karna|kar|karenge|karega|karegi)\\b/i, // Forms of करना (to do)\n      /\\b(bolo|bolta|bolti|bolte|bola|boli|bole|bolna|bol)\\b/i, // Forms of बोलना (to speak)\n      /\\b(jao|jata|jati|jate|gaya|gayi|gaye|jana|ja)\\b/i, // Forms of जाना (to go)\n      /\\b(khao|khata|khati|khate|khaya|khayi|khaye|khana|kha)\\b/i, // Forms of खाना (to eat)\n      /\\b(suno|sunta|sunti|sunte|suna|suni|sune|sunna|sun)\\b/i // Forms of सुनना (to listen)\n    ];\n    \n    // Check for patterns that are strong indicators of Hinglish\n    for (const pattern of hinglishPatterns) {\n      if (pattern.test(text)) {\n        return true;\n      }\n    }\n    \n    // Look for common Hindi word endings\n    const hindiEndingPattern = /\\b\\w+(iye|ogi|ega|enge|engi|ogi|oga|egi|enga|engi)\\b/i;\n    if (hindiEndingPattern.test(text)) {\n      return true;\n    }\n    \n    // Check for sentences that are likely to be Hinglish\n    // Common Hindi sentence structures\n    const commonSentences = [\n      /aap k(ya|i|e) (kar|ho|hai)/i,\n      /kya (ho raha|chal raha|hua)/i,\n      /\\b(theek|accha) hai\\b/i,\n      /kaise ho/i,\n      /\\b(namaste|namaskar)\\b/i\n    ];\n    \n    for (const pattern of commonSentences) {\n      if (pattern.test(text)) {\n        return true;\n      }\n    }\n    \n    return false;\n  }\n\n  const HINGLISH_PHONEME_MAP: { [key: string]: string } = {\n    // Vowels\n    'a': 'ə',      // Short 'a' (schwa), inherent in Hindi consonants\n    'aa': 'aː',    // Long 'a' (आ), as in \"naam\"\n    'i': 'ɪ',      // Short 'i' (इ), as in \"kitna\"\n    'ee': 'iː',    // Long 'i' (ई), as in \"Vaishnavi\" ending\n    'u': 'ʊ',      // Short 'u' (उ), as in \"tum\"\n    'oo': 'uː',    // Long 'u' (ऊ), as in \"soona\"\n    'e': 'eː',     // Long 'e' (ए), as in \"ek\"\n    'ai': 'ɛː',    // 'ai' (ऐ), as in \"kaise\"\n    'o': 'oː',     // Long 'o' (ओ), as in \"bolo\"\n    'au': 'ɔː',    // 'au' (औ), as in \"mausam\"\n  \n    // Common consonant patterns\n    'kh': 'kʰ',    // Aspirated 'k' (ख), as in \"khaana\"\n    'gh': 'gʰ',    // Aspirated 'g' (घ), as in \"ghar\"\n    'ch': 'tʃ',    // 'ch' (च), as in \"chalo\"\n    'jh': 'dʒʰ',   // Aspirated 'j' (झ), as in \"jheel\"\n    'th': 't̪ʰ',   // Aspirated dental 't' (थ), as in \"tha\"\n    'dh': 'd̪ʰ',   // Aspirated dental 'd' (ध), as in \"dhan\"\n    'ph': 'pʰ',    // Aspirated 'p' (फ), as in \"phool\"\n    'bh': 'bʰ',    // Aspirated 'b' (भ), as in \"bhai\"\n    'sh': 'ʃ',     // 'sh' (श), as in \"shaadi\"\n    'ng': 'ŋ',     // Nasal 'ng' (ङ्ग), as in \"rang\"\n    'tt': 'ʈ',     // Retroflex 't' (ट), as in \"theek\"\n    'dd': 'ɖ',     // Retroflex 'd' (ड), as in \"ladka\"\n    'tth': 'ʈʰ',   // Aspirated retroflex 't' (ठ)\n    'ddh': 'ɖʰ',   // Aspirated retroflex 'd' (ढ)\n  \n    // Special consonants\n    'r': 'ɾ',      // Flapped 'r' (र), as in \"raasta\"\n    'n': 'n̪',     // Dental 'n' (न), as in \"naam\"\n    't': 't̪',     // Dental 't' (त), as in \"tum\"\n    'd': 'd̪',     // Dental 'd' (द), as in \"dena\"\n    'k': 'k',      // 'k' (क), as in \"kar\"\n    'g': 'g',      // 'g' (ग), as in \"gaya\"\n    'p': 'p',      // 'p' (प), as in \"paani\"\n    'b': 'b',      // 'b' (ब), as in \"bolo\"\n    'm': 'm',      // 'm' (म), as in \"main\"\n    'y': 'j',      // 'y' (य), as in \"yaad\"\n    'v': 'v',      // 'v' (व), as in \"Vaishnavi\"\n    'w': 'v',      // 'w' mapped to 'v' (व), common in Hinglish\n    'l': 'l',      // 'l' (ल), as in \"ladka\"\n    's': 's',      // 's' (स), as in \"suno\"\n    'h': 'h',      // 'h' (ह), as in \"hai\"\n    'z': 'z',      // 'z' (ज़), as in \"zindagi\"\n    'f': 'f',      // 'f' (फ़), as in \"fark\"\n  };\n\n\nfunction processHinglishText(text: string): string {\n  // Expanded list of common Hinglish words with phonetic mappings\n  const commonHinglishWords: { [key: string]: string } = {\n    'aap': 'aːp',           // आप (you, formal)\n    'tum': 't̪ʊm',         // तुम (you, informal)\n    'main': 'mɛ̃',         // मैं (I)\n    'mein': 'mẽ',          // में (in)\n    'hum': 'hʊm',          // हम (we)\n    'bolo': 'boːloː',      // बोलो (speak)\n    'suno': 'sʊnoː',       // सुनो (listen)\n    'ham': 'həm',          // Alternative spelling for हम\n    'kya': 'kjɑː',         // क्या (what)\n    'kaun': 'kɔːn',        // कौन (who)\n    'kaise': 'kɛːse',      // कैसे (how)\n    'kyun': 'kjũː',        // क्यों (why)\n    'kab': 'kəb',          // कब (when)\n    'kahan': 'kəhãː',      // कहाँ (where)\n    'yahan': 'jəhãː',      // यहाँ (here)\n    'wahan': 'vəhãː',      // वहाँ (there)\n    'hai': 'hɛː',          // है (is)\n    'hain': 'hɛ̃ː',        // हैं (are)\n    'ho': 'hoː',           // हो (are/be)\n    'kar': 'kər',          // कर (do)\n    'rahe': 'rəhe',        // रहे (continuous action)\n    'raha': 'rəhaː',       // रहा (was, masculine)\n    'gaya': 'gəjaː',       // गया (went, masculine)\n    'gayi': 'gəjiː',       // गई (went, feminine)\n    'accha': 'ətʃʰaː',    // अच्छा (good)\n    'theek': 'ʈʰiːk',     // ठीक (fine)\n    'bahut': 'bəhʊt̪',    // बहुत (a lot)\n    'namaste': 'nəməst̪e', // नमस्ते (hello)\n    'namaskar': 'nəməskaːr', // नमस्कार (greetings)\n    'dhanyavaad': 'd̪ʰənjəvaːd̪', // धन्यवाद (thank you)\n    'ghar': 'gʰər',        // घर (house)\n    'ladka': 'ləɖkaː',     // लड़का (boy)\n    'kaam': 'kaːm',        // काम (work)\n    'nahi': 'nəhiː',       // नहीं (no)\n    'tha': 'tʰaː',         // था (was, masculine)\n    'thi': 'tʰiː',         // थी (was, feminine)\n    'the': 'tʰeː',         // थे (were)\n    'jaan': 'dʒaːn',       // जान (life/soul)\n    'pyaar': 'pjaːr',      // प्यार (love)\n    'dost': 'doːst',       // दोस्त (friend)\n    'khana': 'kʰaːnaː',    // खाना (food/to eat)\n    'paani': 'paːniː',     // पानी (water)\n    'bachcha': 'bətʃʰaː', // बच्चा (child)\n    'raasta': 'raːstaː',   // रास्ता (path)\n    'sapna': 'səpnaː',     // सपना (dream)\n    'dil': 'dɪl',          // दिल (heart)\n    'zindagi': 'zɪndəgiː', // ज़िंदगी (life)\n    'samajh': 'səmədʒʰ',  // समझ (understanding)\n    'baat': 'baːt',        // बात (talk)\n    'waqt': 'vəqt',        // वक्त (time)\n    'yaad': 'jaːd',        // याद (memory)\n    'shaadi': 'ʃaːdiː',    // शादी (marriage)\n    'khush': 'kʰʊʃ',      // खुश (happy)\n    'milna': 'mɪlnaː',     // मिलना (to meet)\n    'dekhna': 'deːkʰnaː', // देखना (to see)\n    'sochna': 'soːtʃnaː',  // सोचना (to think)\n    'jaanna': 'dʒaːnnaː', // जानना (to know)\n    'lena': 'leːnaː',      // लेना (to take)\n    'dena': 'deːnaː',      // देना (to give)\n    'chalna': 'tʃəlnaː',   // चलना (to walk)\n    'aana': 'aːnaː',       // आना (to come)\n    'jaana': 'dʒaːnaː',   // जाना (to go)\n    'peena': 'piːnaː',     // पीना (to drink)\n    'sona': 'soːnaː',      // सोना (to sleep)\n    'aaj': 'aːdʒ',         // आज (today)\n    'kal': 'kəl',          // कल (yesterday/tomorrow)\n    'abhi': 'əbʰiː',       // अभी (now)\n    'sab': 'səb',          // सब (all)\n    'kuch': 'kʊtʃ',       // कुछ (some)\n    'thoda': 'tʰoːdaː',    // थोड़ा (little)\n    'zyada': 'zjaːdaː'     // ज़्यादा (more)\n  };\n\n  const words = text.toLowerCase().split(/\\s+/);\n  return words.map(word => {\n    if (commonHinglishWords[word]) {\n      return commonHinglishWords[word];\n    }\n\n    let result = '';\n    let i = 0;\n    while (i < word.length) {\n      // Check two-character patterns first\n      if (i < word.length - 1) {\n        const twoChars = word.substring(i, i + 2);\n        if (HINGLISH_PHONEME_MAP[twoChars]) {\n          result += HINGLISH_PHONEME_MAP[twoChars];\n          i += 2;\n          continue;\n        }\n      }\n\n      // Handle single characters\n      const char = word[i];\n      result += HINGLISH_PHONEME_MAP[char] || char;\n      i++;\n    }\n\n    // Post-process word for Hindi-specific rules\n    // Lengthen final 'i' or 'e' to match Hindi pronunciation\n    result = result.replace(/ɪ$/g, 'iː').replace(/e$/g, 'eː');\n    // Remove schwa before final consonant if unintended\n    result = result.replace(/ə([kgtɖd̪pbɾmn̪lsʃʈ])$/g, '$1');\n    // Add nasalization for 'n' or 'm' at end if applicable\n    result = result.replace(/[nm]$/, '̃');\n\n    return result;\n  }).join(' ');\n} \n\n  // Add function to handle Hindi syllable structure\n  function processHindiSyllable(text: string): string {\n    return text\n      // Handle consonant clusters with virama\n      .replace(/([क-ह])्([क-ह])/g, (_, c1, c2) => {\n        const p1 = HINDI_PHONEME_MAP[c1] || c1;\n        const p2 = HINDI_PHONEME_MAP[c2] || c2;\n        return p1 + p2;\n      })\n      // Handle inherent 'a' sound after consonants, but not at word end\n      .replace(/([क-ह])(?![ािीुूृेैोौ्ंँः]|$)/g, (_, c) => {\n        const phoneme = HINDI_PHONEME_MAP[c] || c;\n        return phoneme + 'ə';\n      })\n      // Handle word-final consonants without schwa\n      .replace(/([क-ह])$/g, (_, c) => HINDI_PHONEME_MAP[c] || c)\n      // Handle nasalization\n      .replace(/([aeiouəɛɔ])ं/g, '$1̃')\n      .replace(/([aeiouəɛɔ])ँ/g, '$1̃');\n  }\n\n  // Define supported language codes explicitly\n  type SupportedLanguage = 'en-us' | 'en-gb' | 'hi' | 'es' | 'fr' | 'zh';\n  \n  export async function phonemize(text: string, language: SupportedLanguage = \"en-us\", norm = true) {\n    // 1. Normalize text\n    if (norm) {\n      text = normalize_text(text);\n    }\n\n    // Directly use the provided language code\n    let targetLanguage = language;\n    \n    // For backward compatibility - map any legacy single-letter codes\n    if (language === 'a' as any) targetLanguage = 'en-us';\n    if (language === 'b' as any) targetLanguage = 'en-gb';\n    if (language === 'h' as any) targetLanguage = 'hi';\n    if (language === 'e' as any) targetLanguage = 'es';\n    if (language === 'f' as any) targetLanguage = 'fr';\n    if (language === 'z' as any) targetLanguage = 'zh';\n    \n    console.log(`Processing text (${text.length} chars) as: ${targetLanguage}`);\n\n    // Check if text is too long - handle with max char limits\n    const MAX_PHONEME_INPUT_LENGTH = 300; // Safe maximum for phonemization\n    \n    if (text.length > MAX_PHONEME_INPUT_LENGTH) {\n      console.warn(`Text too long (${text.length} chars), processing only the first ${MAX_PHONEME_INPUT_LENGTH} characters`);\n      // Truncate at word boundary closest to the limit\n      const truncatedText = text.substring(0, MAX_PHONEME_INPUT_LENGTH).split(' ').slice(0, -1).join(' ');\n      console.log(`Truncated to: \"${truncatedText}\"`);\n      text = truncatedText;\n    }\n\n    // 3. Split into chunks, to ensure we preserve punctuation\n    const sections = split(text, PUNCTUATION_PATTERN);\n\n    // 4. Convert each section to phonemes\n    const ps = (await Promise.all(\n      sections.map(async ({ match, text }) => {\n        if (match) return text;\n        \n        switch (targetLanguage) {\n          case 'hi': // Handles both Devanagari and Romanized Hindi (Hinglish)\n            // Check for Devanagari script\n            const isDevanagari = /[\\u0900-\\u097F]/.test(text);\n            \n            if (isDevanagari) {\n              // For Devanagari script\n              return Array.from(text)\n                .map(char => HINDI_PHONEME_MAP[char] || char)\n                .join('');\n            } else {\n              // For Hinglish (Romanized Hindi)\n              let processed = processHinglishText(text);\n              return processed;\n            }\n          \n          case 'es':\n            let result = text.toLowerCase();\n            result = result\n              .replace(/ch/g, 'tʃ')\n              .replace(/ll/g, 'j')\n              .replace(/rr/g, 'r')\n              .replace(/c([ie])/g, 's$1');\n            \n            return Array.from(result)\n              .map(char => SPANISH_PHONEME_MAP[char] || char)\n              .join('');\n          \n          case 'en-us':\n          case 'en-gb':\n          default: // Default to English using espeakng\n            try {\n              // Pass the correct language code directly to espeakng\n              // Handle potential errors in espeakng more gracefully\n              try {\n                return (await espeakng(text, targetLanguage)).join(\" \");\n              } catch (espeakError) {\n                console.error(`Error with espeakng phonemization for ${targetLanguage}:`, espeakError);\n                // Fallback to character-by-character phoneme mapping for English\n                return text\n                  .replace(/ch/g, 'tʃ')\n                  .replace(/th/g, 'θ')\n                  .replace(/sh/g, 'ʃ')\n                  .replace(/ph/g, 'f');\n              }\n            } catch (error) {\n              console.error(`Unexpected error in phonemization for ${targetLanguage}:`, error);\n              return text; // Ultimate fallback\n            }\n        }\n      })\n    )).join(\"\");\n\n    // 5. Post-process phonemes\n    let processed = ps\n      // General post-processing\n      .replace(/kəkˈoːɹoʊ/g, \"kˈoʊkəɹoʊ\")\n      .replace(/kəkˈɔːɹəʊ/g, \"kˈəʊkəɹəʊ\")\n      .replace(/ʲ/g, \"j\")\n      .replace(/r/g, \"ɹ\")\n      .replace(/x/g, \"k\")\n      .replace(/ɬ/g, \"l\")\n      .replace(/(?<=[a-zɹː])(?=hˈʌndɹɪd)/g, \" \")\n      .replace(/ z(?=[;:,.!?¡¿—…\"«»\"\"(){}[] ]|$)/g, \"z\");\n      \n    // 6. Language-specific post-processing\n    if (targetLanguage === 'en-us') {\n      processed = processed.replace(/(?<=nˈaɪn)ti(?!ː)/g, \"di\");\n    } else if (targetLanguage === 'hi') {\n      // Hindi-specific post-processing\n      processed = processed\n        // Handle aspirated sounds\n        .replace(/(?<=[aeiou])h/g, 'ɦ')\n        // Add space after long vowels for better rhythm\n        .replace(/(?<=\\w)ː/g, 'ː ')\n        // Fix common pronunciation issues\n        .replace(/kəʊn/g, \"kɔːn\") // Fix \"kaun\" pronunciation\n        .replace(/həʊ/g, \"hoː\")   // Fix \"ho\" pronunciation \n        .replace(/([kKgGtTdDpPbB])ə([ɾr])/g, \"$1$2\") // Remove schwa between consonant and 'r'\n        .replace(/([aeiouy])([ɾr])([aeiouy])/g, \"$1$2$3\") // Strengthen 'r' between vowels\n        // Add spacing between syllables for better rhythm\n        .replace(/([kKgGtTdDpPbB][ɦh])/g, \"$1 \")\n        // Ensure proper stress patterns for Hindi\n        .replace(/([aeiou])([^aeiou\\s]+)$/g, \"$1ː$2\"); // Lengthen final vowels before consonant endings\n    } \n    \n    // Ensure the output isn't too long\n    const trimmedResult = processed.trim();\n    \n    // Debug log the phonemization result\n    console.log(`Phonemized ${text.length} chars into ${trimmedResult.length} phoneme chars`);\n    \n    return trimmedResult;\n  }","// Some of this code is from https://github.com/hexgrad/kokoro/\n\nexport const VOICES = Object.freeze({\n  af: {\n    // Default voice is a 50-50 mix of Bella & Sarah\n    name: \"Default\",\n    language: \"en-us\",\n    gender: \"Female\",\n  },\n  af_bella: {\n    name: \"Bella\",\n    language: \"en-us\",\n    gender: \"Female\",\n  },\n  af_nicole: {\n    name: \"Nicole\",\n    language: \"en-us\",\n    gender: \"Female\",\n  },\n  af_sarah: {\n    name: \"Sarah\",\n    language: \"en-us\",\n    gender: \"Female\",\n  },\n  af_sky: {\n    name: \"Sky\",\n    language: \"en-us\",\n    gender: \"Female\",\n  },\n  am_adam: {\n    name: \"Adam\",\n    language: \"en-us\",\n    gender: \"Male\",\n  },\n  am_michael: {\n    name: \"Michael\",\n    language: \"en-us\",\n    gender: \"Male\",\n  },\n\n  bf_emma: {\n    name: \"Emma\",\n    language: \"en-gb\",\n    gender: \"Female\",\n  },\n  bf_isabella: {\n    name: \"Isabella\",\n    language: \"en-gb\",\n    gender: \"Female\",\n  },\n  bm_george: {\n    name: \"George\",\n    language: \"en-gb\",\n    gender: \"Male\",\n  },\n  bm_lewis: {\n    name: \"Lewis\",\n    language: \"en-gb\",\n    gender: \"Male\",\n  },\n  hf_alpha: {\n    name: \"alpha\",\n    language: \"hi\",\n    gender: \"Female\",\n  },\n  hf_beta: {\n    name: \"beta\",\n    language: \"hi\",\n    gender: \"Female\",\n  },\n  hm_omega: {\n    name: \"omega\",\n    language: \"hi\",\n    gender: \"Male\",\n  },\n  hm_psi: {\n    name: \"psi\",\n    language: \"hi\",\n    gender: \"Male\",\n  },\n  ef_dora: {\n    name: \"dora\",\n    language: \"es\",\n    gender: \"Female\",\n  },\n  em_alex: {\n    name: \"alex\",\n    language: \"es\",\n    gender: \"Male\",\n  },\n  em_santa: {\n    name: \"santa\",\n    language: \"es\",\n    gender: \"Male\",\n  },\n  ff_siwis: {\n    name: \"siwis\",\n    language: \"es\",\n    gender: \"Female\",\n  },\n  jf_alpha: {\n    name: \"alpha\",\n    language: \"ja\",\n    gender: \"Female\",\n  },\n  jf_gongitsune: {\n    name: \"gongitsune\",\n    language: \"ja\",\n    gender: \"Female\",\n  },\n  jf_nezumi: {\n    name: \"nezumi\",\n    language: \"ja\",\n    gender: \"Female\",\n  },\n  jf_tebukuro: {\n    name: \"tebukuro\",\n    language: \"ja\",\n    gender: \"Female\",\n  },\n  jm_kumo: {\n    name: \"kumo\",\n    language: \"ja\",\n    gender: \"Male\",\n  },\n  zf_xiaobei: {\n    name: \"xiaobei\",\n    language: \"zh\",\n    gender: \"Female\",\n  },\n  zf_xiaoni: {\n    name: \"xiaoni\",\n    language: \"zh\",\n    gender: \"Female\",\n  },\n  zf_xiaoxiao: {\n    name: \"xiaoxiao\",\n    language: \"zh\",\n    gender: \"Female\",\n  },\n  zf_xiaoyi: {\n    name: \"xiaoyi\",\n    language: \"zh\",\n    gender: \"Female\",\n  },\n  zm_yunjian: {\n    name: \"yunjian\",\n    language: \"zh\",\n    gender: \"Male\",\n  },\n  zm_yunxi: {\n    name: \"yunxi\",\n    language: \"zh\",\n    gender: \"Male\",\n  },\n  zm_yunxia: {\n    name: \"yunxia\",\n    language: \"zh\",\n    gender: \"Male\",\n  },\n  zm_yunyang: {\n    name: \"yunyang\",\n    language: \"zh\",\n    gender: \"Male\",\n  },\n});\n\nconst VOICE_DATA_URL = \"https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX/resolve/main/voices\";\n\n/**\n *\n * @param {keyof typeof VOICES} id\n * @returns {Promise<ArrayBufferLike>}\n */\nasync function getVoiceFile(id: string) {\n  const url = `${VOICE_DATA_URL}/${id}.bin`;\n\n  let cache;\n  try {\n    cache = await caches.open(\"kokoro-voices\");\n    const cachedResponse = await cache.match(url);\n    if (cachedResponse) {\n      return await cachedResponse.arrayBuffer();\n    }\n  } catch (e) {\n    console.warn(\"Unable to open cache\", e);\n  }\n\n  // No cache, or cache failed to open. Fetch the file.\n  const response = await fetch(url);\n  const buffer = await response.arrayBuffer();\n\n  if (cache) {\n    try {\n      // NOTE: We use `new Response(buffer, ...)` instead of `response.clone()` to handle LFS files\n      await cache.put(\n        url,\n        new Response(buffer, {\n          headers: response.headers,\n        }),\n      );\n    } catch (e) {\n      console.warn(\"Unable to cache file\", e);\n    }\n  }\n\n  return buffer;\n}\n\nconst VOICE_CACHE = new Map();\nexport async function getVoiceData(voice: any) {\n  if (VOICE_CACHE.has(voice)) {\n    return VOICE_CACHE.get(voice);\n  }\n\n  const buffer = new Float32Array(await getVoiceFile(voice));\n  VOICE_CACHE.set(voice, buffer);\n  return buffer;\n}","import { StyleTextToSpeech2Model, AutoTokenizer, Tensor } from \"../libs/transformers/transformers\";\nimport { ModelConfig } from '../config/models/types';\nimport { phonemize } from \"../libs/transformers/utils/phonemize\";\nimport { getVoiceData, VOICES } from \"../libs/transformers/utils/voices\";\n\n\nconst STYLE_DIM = 256;\nconst SAMPLE_RATE = 24000;\n\nexport class TTSEngine {\n  private model: StyleTextToSpeech2Model | null = null;\n  private tokenizer: any = null;\n\n  constructor() {\n    this.model = null;\n    this.tokenizer = null;\n  }\n\n  async loadModel(modelConfig: ModelConfig, options: any = {}) {\n    // console.log('Loading TTS model... ', modelConfig.repo, options);\n    try {\n      this.model = await StyleTextToSpeech2Model.from_pretrained(modelConfig.repo, {\n        progress_callback: options.onProgress,\n        dtype: options.dtype || \"fp32\",\n        device:  \"webgpu\",\n      });\n      \n      this.tokenizer = await AutoTokenizer.from_pretrained(modelConfig.repo, {\n        progress_callback: options.onProgress\n      });\n    } catch (error) {\n      console.error('Error loading TTS model:', error);\n      throw error;\n    }\n  }\n\n  async *generateSpeechStream(text: string, options: any = {}): AsyncGenerator<Float32Array> {\n    console.log(\"Streaming flow triggered\"); // Log to confirm streaming is used\n    \n    if (!this.model || !this.tokenizer) {\n      throw new Error('TTS model not initialized');\n    }\n\n    const { voice = \"af_bella\", speed = 1, language = \"en-us\" } = options;\n\n    if (!VOICES.hasOwnProperty(voice)) {\n      console.error(`Voice \"${voice}\" not found. Available voices:`);\n      console.table(VOICES);\n      throw new Error(`Voice \"${voice}\" not found. Should be one of: ${Object.keys(VOICES).join(\", \")}.`);\n    }\n\n    try {\n      // Split long text into manageable chunks\n      // Maximum character limit per chunk (based on testing)\n      const MAX_CHUNK_LENGTH = 250;\n      const textChunks = this.splitTextIntoChunks(text, MAX_CHUNK_LENGTH);\n      console.log(`Text split into ${textChunks.length} chunks for processing`);\n\n      // Process each chunk and collect audio data\n      for (const chunk of textChunks) {\n        // Pass explicit language code directly to phonemize\n        const phonemes = await phonemize(chunk, language);\n        console.log(`Phonemized chunk: ${chunk.length} chars into ${phonemes.length} phoneme chars`);\n\n        const { input_ids } = this.tokenizer(phonemes, {\n          truncation: true,\n        });\n\n        // Select voice style based on number of input tokens\n        const num_tokens = Math.min(Math.max(\n          input_ids.dims.at(-1) - 2, // Without padding\n          0,\n        ), 509);\n\n        // Load voice style\n        const data = await getVoiceData(voice);\n        const offset = num_tokens * STYLE_DIM;\n        const voiceData = data.slice(offset, offset + STYLE_DIM);\n\n        // Prepare model inputs\n        const inputs = {\n          input_ids: input_ids,\n          style: new Tensor(\"float32\", voiceData, [1, STYLE_DIM]),\n          speed: new Tensor(\"float32\", [speed], [1]),\n        };\n\n        // Generate audio for this chunk\n        const output = await this.model._call(inputs);\n        \n        if (!output || !output.waveform) {\n          console.warn('Model returned null or undefined waveform for a chunk, skipping');\n          continue;\n        }\n        \n        // Convert Tensor to Float32Array\n        const chunkAudioData = new Float32Array(output.waveform.data);\n        \n        if (chunkAudioData.length === 0) {\n          console.warn('Generated audio data is empty for a chunk, skipping');\n          continue;\n        }\n\n        // Normalize audio data\n        const maxValue = chunkAudioData.reduce((max, val) => Math.max(max, Math.abs(val)), 0);\n        const normalizedData = maxValue > 0 ? \n          new Float32Array(chunkAudioData.length) : \n          chunkAudioData;\n        \n        if (maxValue > 0) {\n          for (let i = 0; i < chunkAudioData.length; i++) {\n            normalizedData[i] = chunkAudioData[i] / maxValue;\n          }\n        }\n\n        // Yield smaller chunks of the normalized audio data for streaming\n        const streamChunkSize = 4096; // Can be adjusted for performance\n        for (let i = 0; i < normalizedData.length; i += streamChunkSize) {\n          const streamChunk = normalizedData.slice(i, i + streamChunkSize);\n          if (streamChunk.length > 0) {\n            yield streamChunk;\n          }\n        }\n        \n        // Small pause between chunks for natural-sounding speech\n        const pauseSamples = Math.floor(0.2 * SAMPLE_RATE); // 200ms pause\n        const pauseChunk = new Float32Array(pauseSamples).fill(0);\n        yield pauseChunk;\n      }\n    } catch (error) {\n      console.error('Detailed error in generateSpeechStream:', error);\n      throw error;\n    }\n  }\n  \n  // Helper method to split text into manageable chunks\n  private splitTextIntoChunks(text: string, maxChunkLength: number): string[] {\n    // Find natural break points (sentences, clauses) to split text\n    const chunks: string[] = [];\n    \n    // Use regex to split by sentence boundaries but keep punctuation\n    const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];\n    \n    let currentChunk = '';\n    for (const sentence of sentences) {\n      // If adding this sentence would exceed max length and we already have content\n      if (currentChunk.length + sentence.length > maxChunkLength && currentChunk.length > 0) {\n        chunks.push(currentChunk);\n        currentChunk = sentence;\n      } else {\n        // Otherwise add to current chunk\n        currentChunk += sentence;\n      }\n      \n      // If current chunk is already too long, split it at clause boundaries\n      if (currentChunk.length > maxChunkLength) {\n        const clauses = currentChunk.split(/[,;:]/);\n        currentChunk = '';\n        \n        for (const clause of clauses) {\n          if (currentChunk.length + clause.length > maxChunkLength && currentChunk.length > 0) {\n            chunks.push(currentChunk);\n            currentChunk = clause;\n          } else {\n            currentChunk += clause;\n          }\n        }\n      }\n    }\n    \n    // Add any remaining text\n    if (currentChunk.length > 0) {\n      chunks.push(currentChunk);\n    }\n    \n    // If any chunk is still too long, use hard splitting as a fallback\n    return chunks.flatMap(chunk => {\n      if (chunk.length <= maxChunkLength) {\n        return [chunk];\n      } else {\n        // Hard split by character count, trying to break at word boundaries\n        const words = chunk.split(' ');\n        const hardChunks: string[] = [];\n        let currentHardChunk = '';\n        \n        for (const word of words) {\n          if (currentHardChunk.length + word.length + 1 > maxChunkLength) {\n            hardChunks.push(currentHardChunk);\n            currentHardChunk = word;\n          } else {\n            currentHardChunk += (currentHardChunk ? ' ' : '') + word;\n          }\n        }\n        \n        if (currentHardChunk) {\n          hardChunks.push(currentHardChunk);\n        }\n        \n        return hardChunks;\n      }\n    });\n  }\n}\n\n","import {\n  pipeline,\n  TextGenerationPipeline,\n  FeatureExtractionPipeline,\n  AutomaticSpeechRecognitionPipeline,\n  TextToAudioPipeline,\n  ImageToTextPipeline,\n  ImageToImagePipeline,\n  ImageFeatureExtractionPipeline,\n  PipelineType\n} from '../libs/transformers/transformers';\nimport { ModelConfig } from '../config/models/types';\nimport { TTSEngine } from './tts-engine';\nimport { AutoProcessor, MultiModalityCausalLM } from '../libs/transformers/transformers';\n\nexport class TransformersEngineWrapper {\n  private transformersPipeline:\n    | TextGenerationPipeline\n    | FeatureExtractionPipeline\n    | AutomaticSpeechRecognitionPipeline\n    | TextToAudioPipeline\n    | ImageToTextPipeline\n    | ImageToImagePipeline\n    | ImageFeatureExtractionPipeline\n    | null = null;\n  private modelType: string | null = null;\n  private ttsEngine: TTSEngine | null = null;\n  private imageProcessor: any | null = null;\n  private multimodalModel: any | null = null;\n\n  constructor() {\n    this.transformersPipeline = null;\n    this.modelType = null;\n  }\n\n  async loadModel(modelConfig: ModelConfig, options: any = {}) {\n    try {\n      // Validate required model config properties\n      if (!modelConfig.modelType) {\n        throw new Error('Model configuration missing required \"modelType\" property');\n      }\n      if (!modelConfig.repo) {\n        throw new Error('Model configuration missing required \"repo\" property');\n      }\n\n      this.modelType = modelConfig.modelType;\n      \n      options.device = 'webgpu';\n\n      // Configure pipeline options with proper worker settings\n      const pipelineOptions = {\n        progress_callback: options.onProgress || (() => {}),\n        ...options\n      };\n\n      // Handle TTS models first, before attempting to create other pipelines\n      if (modelConfig.modelType === 'text-to-speech') {\n        this.ttsEngine = new TTSEngine();\n        console.log('Loading TTS model...');\n        await this.ttsEngine.loadModel(modelConfig, options);\n        console.log('TTS model loaded');\n        return; // Exit early for TTS models\n      }\n\n      // Initialize image processor for multimodal models\n      if (modelConfig.modelType === 'multimodal') {\n        options.device = \"webgpu\";\n        // console.log('Loading multimodal model...');\n        this.imageProcessor = await AutoProcessor.from_pretrained(modelConfig.repo, pipelineOptions);\n        // console.log('Image processor loaded');\n        this.multimodalModel = await MultiModalityCausalLM.from_pretrained(modelConfig.repo, pipelineOptions);\n        // console.log('Multimodal model loaded');\n        return;\n      }\n\n      // For non-TTS models, create the appropriate pipeline\n      const pipelineType = modelConfig.pipeline as PipelineType;\n      this.transformersPipeline = await pipeline(pipelineType, modelConfig.repo, pipelineOptions);\n\n    } catch (error) {\n      console.error('Error loading Transformers model:', error);\n      const message = error instanceof Error ? error.message : String(error);\n      throw new Error(`Failed to load Transformers model \"${modelConfig.modelName}\": ${message}`);\n    }\n  }\n\n  // Text generation specific method\n  async generateText(input: string | Array<{ role: string; content: string }>, options: any = {}) {\n    if (!this.transformersPipeline || this.modelType !== 'text-generation') {\n      throw new Error('Text generation pipeline not initialized.');\n    }\n\n    let messages = Array.isArray(input) ? input : [];\n\n    // If input is a string, construct messages array\n    if (typeof input === 'string') {\n      if (options.system_prompt) {\n        messages.push({ role: 'system', content: options.system_prompt });\n      }\n      messages.push({ role: 'user', content: input });\n    }\n\n    // Convert messages array to text format\n    const prompt = messages.map((m) => `${m.role}: ${m.content}`).join('\\n');\n\n    const result = await (this.transformersPipeline as any)(prompt, {\n      temperature: options.temperature ?? 0.1,\n      max_new_tokens: options.max_new_tokens ?? 300,\n      repetition_penalty: options.repetition_penalty,\n      no_repeat_ngram_size: options.no_repeat_ngram_size,\n      num_beams: options.num_beams,\n      num_return_sequences: options.num_return_sequences,\n      ...options,\n    });\n    return result;\n  }\n\n  // Feature extraction specific method\n  async extractFeatures(text: string, options: any = {}) {\n    if (!this.transformersPipeline || this.modelType !== 'feature-extraction') {\n      throw new Error('Feature extraction pipeline not initialized.');\n    }\n    return await (this.transformersPipeline as any)(text, {\n      pooling: options.pooling ?? 'mean',\n      normalize: options.normalize ?? true,\n      ...options,\n    });\n  }\n\n  // Speech recognition specific method\n  async transcribe(audioInput: Float32Array | Float64Array | string | Blob, options: any = {}) {\n    if (!this.transformersPipeline || this.modelType !== 'automatic-speech-recognition') {\n      throw new Error('Speech recognition pipeline not initialized.');\n    }\n\n    const input = audioInput instanceof Blob ? new Float32Array(await audioInput.arrayBuffer()) : (audioInput as any);\n\n    const result = await (this.transformersPipeline as any)(input, {\n      language: options.language,\n      task: options.task,\n      return_timestamps: options.return_timestamps,\n      chunk_length_s: options.chunk_length_s,\n      stride_length_s: options.stride_length_s,\n      ...options,\n    });\n    return result;\n  }\n\n  // Streaming text-to-speech method\n  async textToSpeechStream(text: string, options: any = {}) {\n    if (!this.ttsEngine) {\n      throw new Error('Text-to-speech engine not initialized.');\n    }\n    \n    try {\n      // Find the selected voice's language from options or fallback\n      const stream = this.ttsEngine.generateSpeechStream(text, options);\n      \n      // Return both the stream and the sample rate needed for playback\n      return {\n        stream: stream,\n        sampleRate: 24000 // Hardcoded based on kokoro-tts's known sample rate\n      };\n    } catch (error) {\n      console.error('Error in text-to-speech stream:', error);\n      throw error;\n    }\n  }\n\n  // Generic method for backward compatibility\n  async generate(prompt: string, options: any = {}) {\n    switch (this.modelType) {\n      case 'text-generation':\n        return this.generateText(prompt, options);\n      case 'feature-extraction':\n        return this.extractFeatures(prompt, options);\n      case 'automatic-speech-recognition':\n        return this.transcribe(prompt, options);\n      case 'text-to-speech':\n        throw new Error('Direct text-to-speech is no longer supported. Use textToSpeechStream instead.');\n      default:\n        throw new Error(`Unsupported model type: ${this.modelType}`);\n    }\n  }\n\n  async embed(input: string, options: any = {}) {\n    if (!this.transformersPipeline || this.modelType !== 'feature-extraction') {\n      console.debug(`Feature extraction pipeline not initialized. ${input}, ${options}`);\n      throw new Error('Feature extraction pipeline not initialized.');\n    }\n  }\n\n  async generateImage(input: { text: string }, options: any = {}) {\n    if (this.modelType !== 'multimodal') {\n      throw new Error('Multimodal model not initialized.');\n    }\n\n    if (!this.imageProcessor || !this.multimodalModel) {\n      throw new Error('Image processor or multimodal model not initialized.');\n    }\n\n    try {\n      const conversation = [{ 'role': 'user', 'content': input.text }];\n      \n      // Process the input text with the image processor\n      const inputs = await this.imageProcessor(conversation, {\n        chat_template: \"text_to_image\",\n        ...options\n      });\n\n      // Generate the image\n      const num_image_tokens = this.imageProcessor.num_image_tokens;\n\n      const outputs = await this.multimodalModel.generate({\n        ...inputs,\n        min_new_tokens: num_image_tokens,\n        max_new_tokens: num_image_tokens,\n        do_sample: true,\n      });\n\n      return outputs;\n    } catch (error) {\n      console.error('Error generating image:', error);\n      throw error;\n    }\n  }\n}\n","{\n    \"llama-3.2-1b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Llama-3.2-1B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Llama-3.2-1B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\",\n            \"q0f32\",\n            \"q0f16\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 2048\n        },\n        \"pipeline\": \"text-generation\"\n    },\n    \"llama-3.2-3b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Llama-3.2-3B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Llama-3.2-3B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 2048\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"download_size_in_mb\": {\n                \"q4f16_1\": 1797,\n                \"q4f32_1\": 1797\n            },\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 1797,\n                \"q4f32_1\": 1797\n            }\n        }\n    },\n    \"hermes-llama-3.2-3b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"hermes-llama-3.2-3b\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Hermes-3-Llama-3.2-3B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 2048\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"download_size_in_mb\": {\n                \"q4f16_1\": 1797,\n                \"q4f32_1\": 1797\n            },\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 1797,\n                \"q4f32_1\": 1797\n            }\n        }\n    },\n    \"qwen2.5-3b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen2.5-3B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen2.5-3B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\"q4f32_1\"],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 4096\n        },\n        \"pipeline\": \"text-generation\"\n    },  \n    \"smollm2-135m-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"SmolLM2-135M-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/SmolLM2-135M-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q0f32\",\n            \"q0f16\"\n        ],\n        \"defaultQuantization\": \"q0f32\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 2048\n        },\n        \"required_features\": [\n            \"shader-f16\"\n        ],\n        \"overrides\": {\n            \"context_window_size\": 4096\n        },\n        \"pipeline\": \"text-generation\"\n    },\n    \"smollm2-360m-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"SmolLM2-360M-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/SmolLM2-360M-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\",\n            \"q0f32\",\n            \"q0f16\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"required_features\": [\n            \"shader-f16\"\n        ],\n        \"defaultParams\": {\n            \"temperature\": 0.1,\n            \"maxTokens\": 2048\n        },\n        \"pipeline\": \"text-generation\"\n    },\n    \"smollm2-1.7b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"SmolLM2-1.7B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/SmolLM2-1.7B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\",\n        \"defaultParams\": {\n            \"temperature\": 0.1,\n            \"maxTokens\": 2048\n        }\n    },\n    \"qwen2.5-0.5b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen2.5-0.5B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen2.5-0.5B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\",\n            \"q0f32\",\n            \"q0f16\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"gemma-2b-it\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"gemma-2b-it\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/gemma-2b-it-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\",\n        \"required_features\": [\n            \"shader-f16\"\n        ]\n    },\n    \"tinyllama-1.1b-chat-v0.4\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"TinyLlama-1.1B-Chat-v0.4\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/TinyLlama-1.1B-Chat-v0.4-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"phi-3.5-mini-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Phi-3.5-mini-instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Phi-3.5-mini-instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"qwen2.5-1.5b-instruct\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen2.5-1.5B-Instruct\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen2.5-1.5B-Instruct-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"deepseek-r1-distill-qwen-1.5b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"DeepSeek-R1-Distill-Qwen-1.5B-MLC\",\n        \"modelType\": \"text-generation\",\n        \"modelLibrary\": \"Qwen2-1.5B-Instruct-q4f32_1-ctx4k_cs1k-webgpu.wasm\",\n        \"repo\": \"sauravpanda/DeepSeek-R1-Distill-Qwen-1.5B-MLC\",\n        \"quantizations\": [\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"deepseek-r1-distill-qwen-7b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"DeepSeek-R1-Distill-Qwen-7B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/DeepSeek-R1-Distill-Qwen-7B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"deepseek-r1-distill-llama-8b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"DeepSeek-R1-Distill-Llama-8B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/DeepSeek-R1-Distill-Llama-8B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"pipeline\": \"text-generation\"\n    },\n    \"snowflake-arctic-embed-m-b4\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"snowflake-arctic-embed-m-b4\",\n        \"modelType\": \"embedding\",\n        \"repo\": \"mlc-ai/snowflake-arctic-embed-m-{quantization}-MLC-b4\",\n        \"quantizations\": [\n            \"q0f32\"\n        ],\n        \"defaultQuantization\": \"q0f32\",\n        \"pipeline\": \"embedding\",\n        \"metadata\": {\n            \"context_window_size\": 512,\n            \"download_size_in_mb\": {\n                \"q0f32\": 218\n            },\n            \"estimated_vram_in_mb\": {\n                \"q0f32\": 218\n            }\n        }\n    },\n    \"snowflake-arctic-embed-s-b4\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"snowflake-arctic-embed-s-b4\",\n        \"modelType\": \"embedding\",\n        \"repo\": \"mlc-ai/snowflake-arctic-embed-s-{quantization}-MLC-b4\",\n        \"quantizations\": [\n            \"q0f32\"\n        ],\n        \"defaultQuantization\": \"q0f32\",\n        \"pipeline\": \"embedding\",\n        \"metadata\": {\n            \"context_window_size\": 512,\n            \"download_size_in_mb\": {\n                \"q0f32\": 66.4\n            },\n            \"estimated_vram_in_mb\": {\n                \"q0f32\": 66.4\n            }\n        }\n    },\n    \"snowflake-arctic-embed-m-b32\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"snowflake-arctic-embed-m-b32\",\n        \"modelType\": \"embedding\",\n        \"repo\": \"mlc-ai/snowflake-arctic-embed-m-{quantization}-MLC-b32\",\n        \"quantizations\": [\n            \"q0f32\"\n        ],\n        \"defaultQuantization\": \"q0f32\",\n        \"pipeline\": \"embedding\",\n        \"metadata\": {\n            \"context_window_size\": 512,\n            \"download_size_in_mb\": {\n                \"q0f32\": 218\n            },\n            \"estimated_vram_in_mb\": {\n                \"q0f32\": 218\n            }\n        }\n    },\n    \"snowflake-arctic-embed-s-b32\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"snowflake-arctic-embed-s-b32\",\n        \"modelType\": \"embedding\",\n        \"repo\": \"mlc-ai/snowflake-arctic-embed-s-{quantization}-MLC-b32\",\n        \"quantizations\": [\n            \"q0f32\"\n        ],\n        \"defaultQuantization\": \"q0f32\",\n        \"pipeline\": \"embedding\",\n        \"metadata\": {\n            \"context_window_size\": 512,\n            \"download_size_in_mb\": {\n                \"q0f32\": 66.4\n            },\n            \"estimated_vram_in_mb\": {\n                \"q0f32\": 66.4\n            }\n        }\n    },\n    \"qwen3-0.6b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen3-0.6B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen3-0.6B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\",\n            \"q0f16\",\n            \"q0f32\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 4096\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 1403.34,\n                \"q4f32_1\": 1924.98,\n                \"q0f16\": 2220.38,\n                \"q0f32\": 3843.25\n            }\n        }\n    },\n    \"qwen3-1.7b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen3-1.7B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen3-1.7B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 4096\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 2036.66,\n                \"q4f32_1\": 2635.44\n            }\n        }\n    },\n    \"qwen3-4b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen3-4B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen3-4B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 4096\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 3431.59,\n                \"q4f32_1\": 4327.71\n            }\n        }\n    },\n    \"qwen3-8b\": {\n        \"engine\": \"mlc\",\n        \"modelName\": \"Qwen3-8B\",\n        \"modelType\": \"text-generation\",\n        \"repo\": \"mlc-ai/Qwen3-8B-{quantization}-MLC\",\n        \"quantizations\": [\n            \"q4f16_1\",\n            \"q4f32_1\"\n        ],\n        \"defaultQuantization\": \"q4f32_1\",\n        \"defaultParams\": {\n            \"temperature\": 0.7,\n            \"maxTokens\": 4096\n        },\n        \"pipeline\": \"text-generation\",\n        \"metadata\": {\n            \"context_window_size\": 4096,\n            \"estimated_vram_in_mb\": {\n                \"q4f16_1\": 5695.78,\n                \"q4f32_1\": 6852.55\n            }\n        }\n    }\n}","{\n  \"llama-3.2-1b-instruct\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"Llama-3.2-1b-Instruct\",\n    \"modelType\": \"text-generation\",\n    \"repo\": \"Xenova/llama-3.2-1b-instruct\",\n    \"pipeline\": \"text-generation\",\n    \"defaultParams\": {\n      \"temperature\": 0.7,\n      \"maxLength\": 2048\n    },\n    \"defaultQuantization\": \"q4\"\n  },\n  \"whisper-tiny-en\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"whisper-tiny-en\",\n    \"modelType\": \"automatic-speech-recognition\",\n    \"repo\": \"onnx-community/whisper-tiny.en\",\n    \"pipeline\": \"automatic-speech-recognition\",\n    \"defaultQuantization\": \"q4\",\n    \"quantizations\": [\"q4\", \"fp16\", \"int4\"]\n  },\n  \"whisper-base-all\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"whisper-base-all\",\n    \"modelType\": \"automatic-speech-recognition\",\n    \"repo\": \"onnx-community/whisper-base_timestamped\",\n    \"pipeline\": \"automatic-speech-recognition\",\n    \"defaultQuantization\": \"q4\",\n    \"quantizations\": [\"q4\", \"fp16\", \"int4\"]\n  },\n  \"whisper-small-all\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"whisper-small-all\",\n    \"modelType\": \"automatic-speech-recognition\",\n    \"repo\": \"onnx-community/whisper-small_timestamped\",\n    \"pipeline\": \"automatic-speech-recognition\",\n    \"defaultQuantization\": \"q4\",\n    \"quantizations\": [\"q4\", \"fp16\", \"int4\"]\n  },\n  \"kokoro-tts\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"kokoro-tts\",\n    \"modelType\": \"text-to-speech\",\n    \"repo\": \"onnx-community/Kokoro-82M-v1.0-ONNX\",\n    \"pipeline\": \"text-to-speech\",\n    \"defaultQuantization\": \"fp32\",\n    \"quantizations\": [\"q4\", \"q8\", \"fp32\", \"fp16\", \"q4f16\"],\n    \"defaultParams\": {\n      \"language\": \"en\"\n    }\n  },\n  \"janus-1.3b\": {\n    \"engine\": \"transformers\",\n    \"modelName\": \"Janus-1.3B-ONNX\",\n    \"modelType\": \"multimodal\",\n    \"repo\": \"onnx-community/Janus-1.3B-ONNX\",\n    \"pipeline\": \"multimodal\",\n    \"defaultQuantization\": \"q4f16\",\n    \"quantizations\": [\"q4\", \"q8\", \"fp32\", \"fp16\", \"q4f16\"],\n    \"defaultParams\": {\n    }\n  }\n} ","// src/index.js (Main entry point)\n\nimport { MLCEngineWrapper } from '../../engines/mlc-engine-wrapper';\nimport { TransformersEngineWrapper } from '../../engines/transformer-engine-wrapper';\nimport { ModelConfig, MLCConfig, TransformersConfig } from '../../config/models/types';\nimport mlcModels from '../../config/models/mlc-models.json';\nimport transformersModels from '../../config/models/transformers-models.json';\n\n// Combine model configurations\nconst MODEL_CONFIG: Record<string, ModelConfig> = {\n  ...(mlcModels as Record<string, MLCConfig>),\n  ...(transformersModels as Record<string, TransformersConfig>),\n};\n\nexport class BrowserAI {\n  private engine: MLCEngineWrapper | TransformersEngineWrapper | null;\n  public currentModel: ModelConfig | null;\n  private mediaRecorder: MediaRecorder | null = null;\n  private audioChunks: Blob[] = [];\n  private modelIdentifier: string | null = null;\n  private customModels: Record<string, ModelConfig> = {};\n\n  constructor() {\n    this.engine = null;\n    this.currentModel = null;\n  }\n\n  registerCustomModel(modelIdentifier: string, modelConfig: ModelConfig): void {\n    if (MODEL_CONFIG[modelIdentifier]) {\n      console.warn(`Overriding existing model with identifier \"${modelIdentifier}\"`);\n    }\n    this.customModels[modelIdentifier] = modelConfig;\n  }\n\n  async loadModel(modelIdentifier: string, options: Record<string, unknown> = {}): Promise<void> {\n    this.modelIdentifier = modelIdentifier;\n    // Check custom models first, then fall back to built-in models\n    const modelConfig = this.customModels[this.modelIdentifier] || MODEL_CONFIG[this.modelIdentifier];\n    if (!modelConfig) {\n      throw new Error(`Model identifier \"${this.modelIdentifier}\" not recognized.`);\n    }\n\n    // Check if model exists in both MLC and Transformers configs\n    const mlcVersion = (mlcModels as Record<string, MLCConfig>)[this.modelIdentifier];\n    // const transformersVersion = (transformersModels as Record<string, TransformersConfig>)[modelIdentifier];\n\n    // For text-generation models, prefer MLC if available\n    let engineToUse = modelConfig.engine;\n    if (modelConfig.modelType === 'text-generation' && mlcVersion) {\n      engineToUse = 'mlc';\n    }\n\n    switch (engineToUse) {\n      case 'mlc':\n        this.engine = new MLCEngineWrapper();\n        await this.engine.loadModel(mlcVersion || modelConfig, options);\n        break;\n      case 'transformers':\n        this.engine = new TransformersEngineWrapper();\n        await this.engine.loadModel(modelConfig, options);\n        break;\n      default:\n        throw new Error(`Engine \"${engineToUse}\" not supported.`);\n    }\n\n    this.currentModel = modelConfig;\n  }\n\n  async generateText(prompt: string, options: Record<string, unknown> = {}): Promise<unknown> {\n    if (!this.engine) {\n      throw new Error('No model loaded. Please call loadModel first.');\n    }\n\n    try {\n      const result = await this.engine.generateText(prompt, options);\n      return result;\n    } catch (error) {\n      console.error('Error generating text:', error);\n      throw error;\n    }\n  }\n\n  async embed(input: string, options: Record<string, unknown> = {}): Promise<unknown> {\n    if (!this.engine) {\n      throw new Error('No model loaded. Please call loadModel first.');\n    }\n    return await this.engine.embed(input, options);\n  }\n\n  async transcribeAudio(audio: Blob | Float32Array, options: Record<string, unknown> = {}): Promise<unknown> {\n    if (!this.engine) {\n      throw new Error('No model loaded. Please call loadModel first.');\n    }\n\n    try {\n      if (this.engine instanceof TransformersEngineWrapper) {\n        if (audio instanceof Blob) {\n          const audioContext = new AudioContext({\n            sampleRate: 16000, // Force 16kHz sample rate\n          });\n\n          const arrayBuffer = await audio.arrayBuffer();\n          const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n\n          // Ensure we get the correct number of samples\n          const float32Data = new Float32Array(Math.floor(audioBuffer.length));\n          audioBuffer.copyFromChannel(float32Data, 0);\n\n          // Clean up\n          audioContext.close();\n\n          return await this.engine.transcribe(float32Data, options);\n        }\n        return await this.engine.transcribe(audio, options);\n      } else {\n        throw new Error('Engine does not support transcribe method.');\n      }\n    } catch (error) {\n      console.error('Transcription error:', error);\n      throw error;\n    }\n  }\n\n  async startRecording(): Promise<void> {\n    if (this.mediaRecorder) {\n      throw new Error('Recording already in progress');\n    }\n\n    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n    this.mediaRecorder = new MediaRecorder(stream);\n    this.audioChunks = [];\n\n    this.mediaRecorder.ondataavailable = (event) => {\n      if (event.data.size > 0) {\n        this.audioChunks.push(event.data);\n      }\n    };\n\n    this.mediaRecorder.start();\n  }\n\n  async stopRecording(): Promise<Blob> {\n    return new Promise((resolve, reject) => {\n      if (!this.mediaRecorder || this.mediaRecorder.state === 'inactive') {\n        reject(new Error('No recording in progress'));\n        return;\n      }\n\n      this.mediaRecorder.onstop = () => {\n        const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });\n        this.audioChunks = [];\n        this.mediaRecorder = null;\n        resolve(audioBlob);\n      };\n\n      this.mediaRecorder.stop();\n    });\n  }\n\n  async generateResponse(text: string): Promise<string> {\n    if (!this.modelIdentifier) {\n      throw new Error('No model loaded. Please call loadModel first.');\n    }\n    if (this.currentModel?.modelName !== this.modelIdentifier) {\n      await this.loadModel(this.modelIdentifier);\n    }\n    const response = await this.generateText(text);\n    return response as string;\n  }\n\n  async textToSpeech(text: string, options: Record<string, unknown> = {}): Promise<any> {\n    // Check if engine is already loaded\n    if (!this.engine) {\n      // Load the transformers engine if not already loaded\n      this.engine = new TransformersEngineWrapper();\n      await this.engine.loadModel(MODEL_CONFIG['kokoro-tts'], {\n        quantized: true,\n        device: 'webgpu',\n        ...options,\n      });\n    }\n\n    try {\n      if (this.engine instanceof TransformersEngineWrapper) {\n        // Use the streaming method\n        return await this.engine.textToSpeechStream(text, options);\n      } else {\n        throw new Error('Current engine does not support text-to-speech streaming');\n      }\n    } catch (error) {\n      console.error('Error generating speech stream:', error);\n      throw error;\n    }\n  }\n\n  async generateImage(text: string, options: Record<string, unknown> = {}): Promise<string> {\n    if (!this.modelIdentifier) {\n      throw new Error('No model loaded. Please call loadModel first.');\n    }\n\n    if (this.currentModel?.modelType !== 'multimodal') {\n      throw new Error('Current model does not support multimodal inputs.');\n    }\n\n    if (this.engine instanceof TransformersEngineWrapper) {\n      const response = await this.engine.generateImage({\n        text: text as string,\n      }, options);\n      return response;\n    }\n\n    throw new Error('Current engine does not support multimodal generation');\n  }\n\n  async clearModelCache(): Promise<void> {\n    return new Promise<void>(async (resolve, reject) => {\n      try {\n        // MLC models are stored in Cache Storage with specific prefixes\n        const cacheNames = ['webllm/config', 'webllm/wasm', 'webllm/model'];\n        \n        // Get all cache names\n        const existingCacheNames = await caches.keys();\n        \n        // Filter caches that match our MLC prefixes\n        const mlcCaches = existingCacheNames.filter(name => \n          cacheNames.some(prefix => name.includes(prefix))\n        );\n        \n        // Delete all matching caches\n        await Promise.all(mlcCaches.map(name => caches.delete(name)));\n        \n        console.log('Successfully cleared MLC model cache');\n        resolve();\n      } catch (error) {\n        console.error('Error clearing model cache:', error);\n        reject(error);\n      }\n    });\n  }\n\n  async clearSpecificModelCache(modelIdentifier: string): Promise<void> {\n    if (!this.engine || !(this.engine instanceof MLCEngineWrapper)) {\n      throw new Error('MLC Engine not initialized.');\n    }\n    \n    try {\n      await this.engine.clearSpecificModel(modelIdentifier);\n      console.log(`Successfully cleared cache for model: ${modelIdentifier}`);\n    } catch (error) {\n      console.error(`Error clearing model cache for ${modelIdentifier}:`, error);\n      throw error;\n    }\n  }\n\n  dispose() {\n    if (this.engine instanceof MLCEngineWrapper) {\n      this.engine.dispose();\n    }\n    this.engine = null;\n    this.currentModel = null;\n  }\n}\n","import { Storable, Database, DatabaseConfig } from '../types';\nimport { Storage, StorageFactory } from '../storage';\n\n\nclass IndexedDBStorage<T extends Storable> implements Storage<T> {\n    private dbName: string;\n    private version: number;\n    private storeName: string;\n    private db: IDBDatabase | null = null;\n\n    constructor(config: DatabaseConfig) {\n      this.dbName = config.databaseName;\n      this.version = config.version || 1;\n      this.storeName = config.storeName || 'BrowserAIStore';\n\n    }\n\n\n    private async openDatabase(): Promise<IDBDatabase> {\n        return new Promise((resolve, reject) => {\n            if(this.db){\n                resolve(this.db)\n                return;\n            }\n\n          const request = indexedDB.open(this.dbName, this.version);\n\n          request.onerror = (event) => {\n            reject(`Database error: ${(event.target as IDBRequest).error}`);\n          };\n\n          request.onsuccess = (event) => {\n            this.db = (event.target as IDBRequest).result;\n            resolve(this.db);\n          };\n\n           request.onupgradeneeded = (event) => {\n            const db = (event.target as IDBRequest).result;\n\n            if (!db.objectStoreNames.contains(this.storeName)) {\n              db.createObjectStore(this.storeName, { keyPath: 'id' });\n            }\n          };\n        });\n      }\n\n\n    async store(data: T): Promise<void> {\n         const db = await this.openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readwrite');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.add(data);\n\n          request.onsuccess = () => resolve();\n          request.onerror = (event) => reject(`Error storing data: ${(event.target as IDBRequest).error}`);\n        });\n      }\n\n      async get(id: string): Promise<T | undefined> {\n        const db = await this.openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readonly');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.get(id);\n\n          request.onsuccess = (event) => resolve((event.target as IDBRequest).result as T);\n          request.onerror = (event) => reject(`Error getting data: ${(event.target as IDBRequest).error}`);\n        });\n      }\n\n     async getAll(): Promise<T[]> {\n         const db = await this.openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readonly');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.getAll();\n\n          request.onsuccess = (event) => resolve((event.target as IDBRequest).result as T[]);\n          request.onerror = (event) => reject(`Error getting data: ${(event.target as IDBRequest).error}`);\n        });\n      }\n\n\n    async update(data: T): Promise<void> {\n        const db = await this.openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readwrite');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.put(data);\n\n          request.onsuccess = () => resolve();\n          request.onerror = (event) => reject(`Error updating data: ${(event.target as IDBRequest).error}`);\n        });\n      }\n\n    async delete(id: string): Promise<void> {\n        const db = await this.openDatabase();\n        return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readwrite');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.delete(id);\n\n          request.onsuccess = () => resolve();\n          request.onerror = (event) => reject(`Error deleting data: ${(event.target as IDBRequest).error}`);\n        });\n      }\n\n     async clear(): Promise<void> {\n        const db = await this.openDatabase();\n         return new Promise((resolve, reject) => {\n          const transaction = db.transaction([this.storeName], 'readwrite');\n          const store = transaction.objectStore(this.storeName);\n          const request = store.clear();\n\n          request.onsuccess = () => resolve();\n          request.onerror = (event) => reject(`Error clearing data: ${(event.target as IDBRequest).error}`);\n        });\n    }\n\n\n    close(): void {\n        if(this.db){\n            this.db.close()\n            this.db = null\n        }\n      }\n  }\n\n\n export class IndexedDBStorageFactory<T extends Storable> implements StorageFactory<T>{\n   async createStorage(type: string, config: DatabaseConfig): Promise<Storage<T>> {\n       if(type !== 'indexeddb'){\n           throw new Error(`invalid type ${type}`);\n       }\n       return new IndexedDBStorage<T>(config);\n   }\n}","import { Storable, DatabaseConfig } from '../types';\nimport { Storage, StorageFactory } from '../storage';\n\nexport class SqliteStorage<T extends Storable> implements Storage<T> {\n    private db: IDBDatabase | null = null;\n    private readonly storeName: string;\n\n    constructor(config: DatabaseConfig) {\n        this.storeName = config.databaseName || 'defaultStore';\n        this.initDatabase();\n    }\n\n    private async initDatabase(): Promise<void> {\n        return new Promise((resolve, reject) => {\n            const request = indexedDB.open(this.storeName, 1);\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => {\n                this.db = request.result;\n                resolve();\n            };\n\n            request.onupgradeneeded = (event) => {\n                const db = (event.target as IDBOpenDBRequest).result;\n                if (!db.objectStoreNames.contains(this.storeName)) {\n                    db.createObjectStore(this.storeName, { keyPath: 'id' });\n                }\n            };\n        });\n    }\n\n    async store(data: T): Promise<void> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readwrite');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.add(data);\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve();\n        });\n    }\n\n    async get(id: string): Promise<T | undefined> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readonly');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.get(id);\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve(request.result || undefined);\n        });\n    }\n\n    async getAll(): Promise<T[]> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readonly');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.getAll();\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve(request.result);\n        });\n    }\n\n    async update(data: T): Promise<void> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readwrite');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.put(data);\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve();\n        });\n    }\n\n    async delete(id: string): Promise<void> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readwrite');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.delete(id);\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve();\n        });\n    }\n\n    async clear(): Promise<void> {\n        await this.ensureDbReady();\n        return new Promise((resolve, reject) => {\n            const transaction = this.db!.transaction([this.storeName], 'readwrite');\n            const store = transaction.objectStore(this.storeName);\n            const request = store.clear();\n\n            request.onerror = () => reject(request.error);\n            request.onsuccess = () => resolve();\n        });\n    }\n\n    private async ensureDbReady(): Promise<void> {\n        if (!this.db) {\n            await this.initDatabase();\n        }\n    }\n\n    close(): void {\n        if (this.db) {\n            this.db.close();\n            this.db = null;\n        }\n    }\n}\n\nexport class SqliteStorageFactory<T extends Storable> implements StorageFactory<T> {\n    async createStorage(type: string, config: DatabaseConfig): Promise<Storage<T>> {\n        if(type !== 'sqlite'){\n           throw new Error(`invalid type ${type}`);\n       }\n      return new SqliteStorage<T>(config);\n    }\n}","import { Storable, Database, DatabaseOptions, VectorStore } from './types';\nimport { Storage, StorageFactory } from './storage';\nimport { VectorStoreFactory } from './vectorstore';\nimport { IndexedDBStorageFactory } from './implementation/indexeddb';\nimport { SqliteStorageFactory } from './implementation/sqlite';\n\n// placeholder for vectorstore factories\nconst vectorStoreFactories: Record<string, VectorStoreFactory> = {\n\n}\n\n// register storage factories here\nconst storageFactories: Record<string, StorageFactory<any>> = {\n    'indexeddb': new IndexedDBStorageFactory(),\n    'sqlite': new SqliteStorageFactory()\n};\n\n\n\nexport class DatabaseImpl<T extends Storable> implements Database<T> {\n\n  private storage!: Storage<T>;\n  private vectorStore?: VectorStore;\n\n  constructor() {\n  }\n\n  async initialize(options: DatabaseOptions) {\n    if (!storageFactories[options.type]) {\n      throw new Error(`storage type not supported ${options.type}`);\n    }\n    this.storage = await storageFactories[options.type].createStorage(options.type, options.config);\n  }\n\n  async store(data: T): Promise<void> {\n    return this.storage.store(data);\n  }\n\n  async get(id: string): Promise<T | undefined> {\n    return this.storage.get(id);\n  }\n\n  async getAll(): Promise<T[]> {\n    return this.storage.getAll();\n  }\n\n  async update(data: T): Promise<void> {\n    return this.storage.update(data);\n  }\n\n  async delete(id: string): Promise<void> {\n    return this.storage.delete(id);\n  }\n\n  async clear(): Promise<void> {\n    return this.storage.clear();\n  }\n\n  close(): void {\n    if (this.storage) {\n      this.storage.close();\n    }\n  }\n\n  setVectorStore(type: string) : void {\n    if(!vectorStoreFactories[type]){\n        throw new Error(`Vector store type not supported ${type}`);\n    }\n\n    this.vectorStore = vectorStoreFactories[type].createVectorStore(type);\n  }\n\n  async addVector(id: string, vector: number[]) : Promise<void> {\n    if(!this.vectorStore){\n       throw new Error(\"Vector store not initialized\")\n    }\n    await this.vectorStore.add(id, vector);\n  }\n\n\n async searchVector(vector: number[], topK: number): Promise<string[]> {\n     if(!this.vectorStore){\n        throw new Error(\"Vector store not initialized\")\n     }\n    return await this.vectorStore.search(vector, topK);\n  }\n}","export class HTMLCleaner {\n    private tagsToRemove: string[];\n    private attributesToRemove: string[];\n\n    /**\n     * Creates an instance of HTMLCleaner.\n     * @param {string[]} [tagsToRemove] - Array of HTML tags to remove from the content\n     * @param {string[]} [attributesToRemove] - Array of HTML attributes to remove from remaining elements\n     */\n    constructor(tagsToRemove?: string[], attributesToRemove?: string[]) {\n        this.tagsToRemove = tagsToRemove || ['script', 'style', 'noscript', 'svg', 'canvas', 'iframe', 'video', 'audio', 'img', 'nav', 'aside', 'footer', 'header'];\n        this.attributesToRemove = attributesToRemove || ['onclick', 'onload', 'onerror', 'onmouseover', 'onmouseout'];\n        \n        // Apply deduplication to all methods\n        this.applyDeduplicationToAllMethods();\n    }\n\n    /**\n     * Cleans HTML content by removing specified tags and attributes, returning only text content.\n     * @param {string} html - The HTML content to clean\n     * @returns {string} Cleaned text content with excess whitespace removed\n     */\n    clean(html: string): string {\n        let tempElement = document.createElement('div');\n        tempElement.innerHTML = html;\n\n        this.tagsToRemove.forEach(tag => {\n            let elements = tempElement.querySelectorAll(tag);\n            elements.forEach(el => el.remove());\n        });\n\n        const allElements = tempElement.querySelectorAll('*');\n        allElements.forEach(el => {\n            this.attributesToRemove.forEach(attr => el.removeAttribute(attr));\n        });\n\n        let textContent = tempElement.textContent || \"\";\n        textContent = textContent.replace(/\\s+/g, ' ').trim();\n        return this.deduplicateFinalOutput(textContent);\n    }\n\n    /**\n     * Extracts text content from semantically important HTML elements.\n     * @param {string} html - The HTML content to process\n     * @returns {string} Concatenated text content from semantic elements with line breaks\n     */\n    cleanSemantic(html: string): string {\n        let tempElement = document.createElement('div');\n        tempElement.innerHTML = html;\n        let importantText = \"\";\n        const importantTags = ['article', 'main', 'section', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'blockquote', 'code', 'pre', 'em', 'strong', 'a'];\n        importantTags.forEach(tag => {\n            let elements = tempElement.querySelectorAll(tag);\n            elements.forEach(el => {\n                importantText += (el.textContent || \"\") + \"\\n\\n\";\n            });\n        });\n        importantText = importantText.replace(/\\s+/g, ' ').trim();\n        return this.deduplicateFinalOutput(importantText);\n    }\n\n    /**\n     * Extracts information about interactive elements from HTML content.\n     * @param {string} html - The HTML content to process\n     * @returns {string} Formatted string containing information about interactive elements\n     */\n    cleanForInteractive(html: string): string {\n        let tempElement = document.createElement('div');\n        tempElement.innerHTML = html;\n        \n        const interactiveElements = new Set([\n            'a', 'button', 'input', 'select', 'textarea',\n            'details', 'menu', 'menuitem'\n        ]);\n\n        const interactiveRoles = new Set([\n            'button', 'link', 'checkbox', 'radio',\n            'tab', 'menuitem', 'option', 'switch'\n        ]);\n\n        let interactiveContent = \"\";\n        \n        const processElement = (element: Element) => {\n            const tagName = element.tagName.toLowerCase();\n            const role = element.getAttribute('role');\n            \n            if (interactiveElements.has(tagName) || \n                (role && interactiveRoles.has(role))) {\n                // Special handling for input elements\n                if (tagName === 'input') {\n                    const value = (element as HTMLInputElement).value;\n                    interactiveContent += `[${tagName}] ${value}\\n`;\n                } else {\n                    interactiveContent += `[${tagName}] ${element.textContent}\\n`;\n                }\n            }\n        };\n\n        tempElement.querySelectorAll('*').forEach(processElement);\n        return this.deduplicateFinalOutput(interactiveContent.trim());\n    }\n\n    /**\n     * Preserves the hierarchical structure of HTML content, focusing on headings and paragraphs.\n     * @param {string} html - The HTML content to process\n     * @returns {string} Indented text representation of the document's semantic structure\n     */\n    preserveSemanticHierarchy(html: string): string {\n        let tempElement = document.createElement('div');\n        tempElement.innerHTML = html;\n\n        const headingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];\n        let structuredContent = \"\";\n        \n        const processNode = (element: Element, depth: number = 0) => {\n            const tagName = element.tagName.toLowerCase();\n            const indent = '  '.repeat(depth);\n            \n            if (headingLevels.includes(tagName)) {\n                structuredContent += `${indent}${tagName}: ${element.textContent}\\n`;\n            } else if (tagName === 'p' || tagName === 'article') {\n                structuredContent += `${indent}${element.textContent}\\n`;\n            }\n            \n            Array.from(element.children).forEach(child => processNode(child, depth + 1));\n        };\n\n        processNode(tempElement);\n        return this.deduplicateFinalOutput(structuredContent.trim());\n    }\n\n    /**\n     * Deduplicates the final output to remove repeated paragraphs and sections\n     * @param {string} text - The text to deduplicate\n     * @returns {string} Deduplicated text\n     */\n    private deduplicateFinalOutput(text: string): string {\n        // Split text into paragraphs\n        const paragraphs = text.split(/\\n{2,}|\\r\\n{2,}/);\n        const uniqueParagraphs: string[] = [];\n        const seenParagraphs = new Set<string>();\n        \n        // Process each paragraph\n        for (const paragraph of paragraphs) {\n            const trimmed = paragraph.trim();\n            \n            // Skip empty paragraphs\n            if (!trimmed) continue;\n            \n            // Skip if we've seen this exact paragraph before\n            if (seenParagraphs.has(trimmed)) continue;\n            \n            // Check for near-duplicate paragraphs (>80% similarity)\n            let isDuplicate = false;\n            for (const existing of seenParagraphs) {\n                if (this.calculateSimilarity(trimmed, existing) > 0.8) {\n                    isDuplicate = true;\n                    break;\n                }\n            }\n            \n            if (!isDuplicate) {\n                uniqueParagraphs.push(trimmed);\n                seenParagraphs.add(trimmed);\n            }\n        }\n        \n        // Join unique paragraphs back together\n        return uniqueParagraphs.join('\\n\\n');\n    }\n\n    /**\n     * Calculates similarity between two strings (0-1 scale)\n     * @private\n     * @param {string} str1 - First string to compare\n     * @param {string} str2 - Second string to compare\n     * @returns {number} Similarity score between 0 and 1\n     */\n    private calculateSimilarity(str1: string, str2: string): number {\n        // If either string is empty, return 0\n        if (!str1.length || !str2.length) return 0;\n        \n        // If strings are identical, return 1\n        if (str1 === str2) return 1;\n        \n        // If one string contains the other, return a high similarity\n        if (str1.includes(str2) || str2.includes(str1)) {\n            return 0.9;\n        }\n        \n        // Calculate Levenshtein distance\n        const len1 = str1.length;\n        const len2 = str2.length;\n        \n        // Use a simplified approach for long strings to avoid performance issues\n        if (len1 > 100 || len2 > 100) {\n            // Compare first 50 chars, middle 50 chars, and last 50 chars\n            const compareStart = this.calculateLevenshteinSimilarity(\n                str1.substring(0, 50), \n                str2.substring(0, 50)\n            );\n            \n            const mid1Start = Math.max(0, Math.floor(len1 / 2) - 25);\n            const mid2Start = Math.max(0, Math.floor(len2 / 2) - 25);\n            const compareMiddle = this.calculateLevenshteinSimilarity(\n                str1.substring(mid1Start, mid1Start + 50), \n                str2.substring(mid2Start, mid2Start + 50)\n            );\n            \n            const compareEnd = this.calculateLevenshteinSimilarity(\n                str1.substring(Math.max(0, len1 - 50)), \n                str2.substring(Math.max(0, len2 - 50))\n            );\n            \n            // Average the three similarity scores\n            return (compareStart + compareMiddle + compareEnd) / 3;\n        }\n        \n        // For shorter strings, calculate full Levenshtein similarity\n        return this.calculateLevenshteinSimilarity(str1, str2);\n    }\n\n    /**\n     * Calculates Levenshtein similarity between two strings\n     * @private\n     * @param {string} str1 - First string to compare\n     * @param {string} str2 - Second string to compare\n     * @returns {number} Similarity score between 0 and 1\n     */\n    private calculateLevenshteinSimilarity(str1: string, str2: string): number {\n        const len1 = str1.length;\n        const len2 = str2.length;\n        \n        // Create a matrix of size (len1+1) x (len2+1)\n        const matrix: number[][] = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(0));\n        \n        // Initialize the first row and column\n        for (let i = 0; i <= len1; i++) {\n            matrix[i][0] = i;\n        }\n        \n        for (let j = 0; j <= len2; j++) {\n            matrix[0][j] = j;\n        }\n        \n        // Fill the matrix\n        for (let i = 1; i <= len1; i++) {\n            for (let j = 1; j <= len2; j++) {\n                const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n                matrix[i][j] = Math.min(\n                    matrix[i - 1][j] + 1,      // deletion\n                    matrix[i][j - 1] + 1,      // insertion\n                    matrix[i - 1][j - 1] + cost // substitution\n                );\n            }\n        }\n        \n        // Calculate similarity as 1 - (distance / max length)\n        const distance = matrix[len1][len2];\n        const maxLength = Math.max(len1, len2);\n        return 1 - (distance / maxLength);\n    }\n\n    /**\n     * Applies deduplication to all cleaning methods\n     */\n    private applyDeduplicationToAllMethods(): void {\n        // Store original methods\n        const originalClean = this.clean;\n        const originalCleanSemantic = this.cleanSemantic;\n        const originalCleanForInteractive = this.cleanForInteractive;\n        const originalPreserveSemanticHierarchy = this.preserveSemanticHierarchy;\n        \n        // Override methods to apply deduplication\n        this.clean = (html: string): string => {\n            return this.deduplicateFinalOutput(originalClean.call(this, html));\n        };\n        \n        this.cleanSemantic = (html: string): string => {\n            return this.deduplicateFinalOutput(originalCleanSemantic.call(this, html));\n        };\n        \n        this.cleanForInteractive = (html: string): string => {\n            return this.deduplicateFinalOutput(originalCleanForInteractive.call(this, html));\n        };\n        \n        this.preserveSemanticHierarchy = (html: string): string => {\n            return this.deduplicateFinalOutput(originalPreserveSemanticHierarchy.call(this, html));\n        };\n\n    }\n\n    /**\n     * Creates a structured representation of HTML with element IDs for easy reference,\n     * optimized to reduce noise and focus on meaningful content.\n     * @param {string} html - The HTML content to process\n     * @param {Object} options - Configuration options\n     * @param {boolean} [options.includeCodeBlocks=false] - Whether to include code blocks in the output\n     * @param {boolean} [options.includeScripts=false] - Whether to include script content in the output\n     * @returns {Object} Object containing the structured content, element mapping, and reference mapping\n     */\n    cleanWithElementIDs(html: string, options: {\n        includeCodeBlocks?: boolean,\n        includeScripts?: boolean // Note: script tags are removed by default unless includeScripts=true\n    } = {}): {\n        content: string,\n        elements: Record<string, { type: string, text: string, attributes?: Record<string, string> }>,\n        references: Record<string, string | { href?: string, class?: string, selector?: string }>\n    } {\n        const includeCodeBlocks = options.includeCodeBlocks || false;\n        const includeScripts = options.includeScripts || false;\n\n        let tempElement = document.createElement('div');\n        // Use DOMParser for potentially more robust parsing, though innerHTML is often fine\n        // const parser = new DOMParser();\n        // const doc = parser.parseFromString(html, 'text/html');\n        // tempElement = doc.body; // Or work directly with doc.body\n        tempElement.innerHTML = html; // Sticking with innerHTML for simplicity matching original code\n\n        // --- Initial Cleaning ---\n\n        // 1. Remove unwanted elements BEFORE processing\n        this.tagsToRemove.forEach(tag => {\n            // Only remove if not explicitly included (like scripts)\n            if (tag === 'script' && includeScripts) return;\n            // Don't remove interactive elements we want to process\n            if (['a', 'button', 'input', 'select', 'textarea'].includes(tag)) return;\n\n            let elements = tempElement.querySelectorAll(tag);\n            elements.forEach(el => el.remove());\n        });\n\n        // 2. Clean attributes except important ones\n        const allowedAttributes = ['href', 'type', 'value', 'placeholder', 'name', 'checked', 'selected', 'class', 'id', 'for', 'alt', 'title']; // Added for, alt, title\n        const allElements = tempElement.querySelectorAll('*');\n        allElements.forEach(el => {\n            Array.from(el.attributes).forEach(attr => {\n                // Allow all data-* attributes? Maybe not needed for LLM.\n                // if (!allowedAttributes.includes(attr.name) && !attr.name.startsWith('data-')) {\n                if (!allowedAttributes.includes(attr.name)) {\n                    el.removeAttribute(attr.name);\n                }\n            });\n        });\n\n        // --- Processing ---\n\n        const elements: Record<string, { type: string, text: string, attributes?: Record<string, string> }> = {};\n        const references: Record<string, string | { href?: string, class?: string, selector?: string }> = {};\n        let elementCounter = 1;\n\n        // Set to track processed text content to avoid duplicates (mainly for paragraphs/headings)\n        const processedTextContent = new Set<string>();\n\n        // Helper function to create a selector for an element\n        const createSelector = (element: Element): string => {\n            console.log(element);\n            if (!element || !element.tagName) return ''; // Guard against null/undefined elements\n            const tagName = element.tagName.toLowerCase();\n            let selector = tagName;\n\n            // Add ID if available and valid\n            if (element.id && !/\\s/.test(element.id)) { // Ensure ID doesn't contain spaces\n                selector += `#${CSS.escape(element.id)}`; // Use CSS.escape for robustness\n            }\n\n            // Add name attribute for inputs/textareas/selects if no ID/class? (optional enhancement)\n            if (['input', 'select'].includes(tagName) && element.hasAttribute('name') && !element.id && !element.className) {\n                selector += `[name=\"${CSS.escape(element.getAttribute('name') || '')}\"]`;\n            }\n\n            if (['textarea'].includes(tagName) && element.hasAttribute('name')) {\n                selector += `[name=\"${CSS.escape(element.getAttribute('name') || '')}\"]`;\n            }\n\n            // Add classes if available\n            if (element.className && typeof element.className === 'string') {\n                const classes = element.className.split(/\\s+/).filter(Boolean);\n                classes.forEach(cls => {\n                    // Check if class is reasonably valid (optional, but good practice)\n                    if (/^[a-zA-Z0-9_-]+$/.test(cls)) {\n                       selector += `.${CSS.escape(cls)}`;\n                    }\n                });\n            }\n\n            return selector;\n        };\n\n        // Recursive function to process the document\n        const processNode = (node: Node): string => {\n            // 1. Handle Text Nodes\n            if (node.nodeType === Node.TEXT_NODE) {\n                const text = node.textContent?.replace(/\\s+/g, ' ').trim(); // Normalize whitespace\n                return text ? text + ' ' : ''; // Add trailing space for concatenation\n            }\n\n            // 2. Handle Non-Element Nodes (like comments)\n            if (node.nodeType !== Node.ELEMENT_NODE) return '';\n\n            const element = node as Element;\n            const tagName = element.tagName.toLowerCase();\n\n            // 3. Skip elements completely if they are not meant for LLM context\n            // (This check might be redundant if tagsToRemove already handled it, but good safety)\n            const skipElements = ['script', 'style', 'noscript', 'svg', 'canvas', 'iframe']; // Ensure consistency\n             if (skipElements.includes(tagName) && !(tagName === 'script' && includeScripts)) {\n                 return '';\n             }\n\n            let elementId = '';\n            let elementOutputPrefix = '';\n            let elementOutputSuffix = '';\n            let elementContent = '';\n            let processChildren = true; // Flag to control whether to process child nodes\n\n            // --- Handle Specific Element Types ---\n\n            // Headings\n             if (/^h[1-6]$/.test(tagName)) {\n                const level = parseInt(tagName.substring(1));\n                const prefix = '#'.repeat(level);\n                const text = element.textContent?.trim();\n                if (text && !processedTextContent.has(text)) {\n                    elementId = `${tagName}_${elementCounter++}`;\n                    elements[elementId] = { type: tagName, text: text };\n                    references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                    processedTextContent.add(text);\n\n                    // Output format: ## Heading Text [h2_1]\n                    elementOutputPrefix = `${prefix} ${text} `;\n                    elementOutputSuffix = `[${elementId}]\\n\\n`; // Add ID and block spacing\n                    processChildren = false; // Don't process children again, textContent was enough\n                } else {\n                     return ''; // Skip duplicate or empty heading\n                 }\n            }\n            // Links\n            else if (tagName === 'a' && element.hasAttribute('href')) {\n                const text = element.textContent?.trim();\n                const href = element.getAttribute('href') || '';\n\n                // Avoid processing mailto: or javascript: links unless text is significant?\n                // if (href.startsWith('mailto:') || href.startsWith('javascript:')) return '';\n\n                // Process if text is meaningful\n                if (text && text.length > 1) {\n                    // Use combined text+href for uniqueness check if needed, but often text is enough\n                    const uniqueKey = `link:${text}|${href}`;\n                    if (!processedTextContent.has(uniqueKey)) {\n                         elementId = `link_${elementCounter++}`;\n                         const attributes: Record<string, string> = { href: href };\n                         elements[elementId] = { type: 'link', text: text, attributes: attributes };\n                         references[elementId] = { href: href, selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                         processedTextContent.add(uniqueKey);\n\n                         // Output format: Link Text [link_1]\n                         elementOutputPrefix = text; // Get text from children processing instead? Better for nested tags in links.\n                         elementOutputSuffix = ` [${elementId}] `;\n                         // Let children be processed to capture nested formatting (like strong tags)\n                    } else {\n                        // If duplicate link text/href, maybe just output text without ID?\n                        elementOutputPrefix = text + ' ';\n                        processChildren = false; // Avoid reprocessing children if skipping ID\n                    }\n\n                } else {\n                    // Link without meaningful text, maybe skip or just process children?\n                    // return ''; // Option 1: Skip entirely\n                    processChildren = true; // Option 2: Process children within the link tag\n                }\n            }\n            // Buttons\n            else if (tagName === 'button') {\n                const text = element.textContent?.trim() || element.getAttribute('aria-label') || element.getAttribute('title');\n\n                if (text && text.length > 0) {\n                    const uniqueKey = `button:${text}`;\n                    // Allow duplicate button text if needed, maybe use selector for uniqueness?\n                    // const uniqueKey = createSelector(element);\n                    if (!processedTextContent.has(uniqueKey)) {\n                         elementId = `btn_${elementCounter++}`;\n                         const attributes: Record<string, string> = {};\n                         const type = element.getAttribute('type');\n                         const name = element.getAttribute('name');\n                         const value = element.getAttribute('value');\n                         const class_val = element.getAttribute('class'); // Use consistent naming\n\n                         if (type) attributes.type = type;\n                         if (name) attributes.name = name;\n                         if (value) attributes.value = value;\n                         if (class_val) attributes.class = class_val;\n\n                         elements[elementId] = {\n                            type: 'button',\n                            text: text,\n                            attributes: Object.keys(attributes).length > 0 ? attributes : undefined\n                        };\n                         references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                         // processedTextContent.add(uniqueKey); // Add if strict button deduplication is needed\n\n                         // Output format: [Button: Button Text] [btn_1]\n                         elementOutputPrefix = `[Button: ${text}]`;\n                         elementOutputSuffix = ` [${elementId}] `;\n                         processChildren = false; // Button textContent is usually sufficient\n                    } else {\n                        return ''; // Skip duplicate button\n                    }\n                } else {\n                    return ''; // Skip button without text\n                }\n            }\n            // Inputs\n            else if (tagName === 'input') {\n                const type = element.getAttribute('type') || 'text';\n                // Skip hidden inputs unless specifically needed\n                if (type === 'hidden') return '';\n\n                const value = (element as HTMLInputElement).value;\n                const placeholder = element.getAttribute('placeholder');\n                const name = element.getAttribute('name');\n                const checked = (element as HTMLInputElement).checked;\n                const labelText = findLabelText(element); // Helper to find associated label\n\n                const idText = labelText || placeholder || name || type; // Best text descriptor\n\n                elementId = `input_${elementCounter++}`;\n                const attributes: Record<string, string> = { type };\n                if (value && type !== 'password') attributes.value = value; // Don't expose password values\n                if (placeholder) attributes.placeholder = placeholder;\n                if (name) attributes.name = name;\n                if (checked) attributes.checked = 'true';\n                if (labelText) attributes.label = labelText; // Add associated label text\n                 if (element.getAttribute('class')) attributes.class = element.getAttribute('class')!;\n\n                elements[elementId] = {\n                    type: 'input',\n                    text: idText,\n                    attributes\n                };\n                references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n\n                // Output format: [text input label=\"Label\" placeholder=\"Placeholder\"] [input_1]\n                let displayText = `[${type} input`;\n                 if (labelText) displayText += ` label=\"${labelText}\"`;\n                 else if (placeholder) displayText += ` placeholder=\"${placeholder}\"`;\n                 else if (name) displayText += ` name=\"${name}\"`;\n                 // Only show value for specific types maybe? (e.g., not password)\n                 // if (value && type !== 'password') displayText += ` value=\"${value}\"`;\n                 if (checked) displayText += ` (checked)`;\n                displayText += `]`;\n\n                elementOutputPrefix = displayText;\n                elementOutputSuffix = ` [${elementId}] `;\n                processChildren = false; // Inputs don't have meaningful children for content\n            }\n            // Select (Dropdowns)\n            else if (tagName === 'select') {\n                const name = element.getAttribute('name');\n                const labelText = findLabelText(element);\n                const idText = labelText || name || 'dropdown';\n\n                interface OptionData {\n                    value: string;\n                    text: string;\n                    selected?: boolean;\n                }\n\n                const options: OptionData[] = Array.from(element.querySelectorAll('option')).map(opt => {\n                    const optData: OptionData = {\n                        value: opt.getAttribute('value') || opt.textContent || '',\n                        text: opt.textContent || ''\n                    };\n                    if ((opt as HTMLOptionElement).selected) {\n                        optData.selected = true;\n                    }\n                    return optData;\n                });\n                const selectedOption = options.find(opt => opt.selected);\n\n                elementId = `select_${elementCounter++}`;\n                elements[elementId] = {\n                    type: 'select',\n                    text: idText,\n                    attributes: {\n                        name: name || '',\n                        options: JSON.stringify(options), // Store all options for context\n                        ...(selectedOption && {selectedValue: selectedOption.value}), // Add current value if selected\n                        ...(labelText && {label: labelText}),\n                        ...(element.getAttribute('class') && {class: element.getAttribute('class')!})\n                    }\n                };\n                references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n\n                // Output format: [Dropdown label=\"Label\" name=\"Name\" selected=\"Value\"] [select_1]\n                let displayText = `[Dropdown`;\n                if (labelText) displayText += ` label=\"${labelText}\"`;\n                else if (name) displayText += ` name=\"${name}\"`;\n                if (selectedOption) displayText += ` selected=\"${selectedOption.text || selectedOption.value}\"`; // Show selected text or value\n                displayText += `]`;\n\n                elementOutputPrefix = displayText;\n                elementOutputSuffix = ` [${elementId}] `;\n                processChildren = false; // Options are handled above\n            }\n            // ** Textareas **\n            else if (tagName === 'textarea') {\n                // const value = (element as HTMLTextAreaElement)?.value; // Current value\n                const placeholder = element.getAttribute('placeholder');\n                const name = element.getAttribute('name');\n                 const labelText = findLabelText(element);\n                 const idText = labelText || placeholder || name || 'text area';\n\n                elementId = `textarea_${elementCounter++}`;\n                const attributes: Record<string, string> = {};\n                // Include value? Might be too verbose for LLM, depends on use case.\n                // if (value) attributes.value = value;\n                if (placeholder) attributes.placeholder = placeholder;\n                if (name) attributes.name = name;\n                if (labelText) attributes.label = labelText;\n                 if (element.getAttribute('class')) attributes.class = element.getAttribute('class')!;\n\n                elements[elementId] = {\n                    type: 'textarea',\n                    text: idText, // Use label/placeholder/name for identification text\n                    attributes\n                };\n                references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n\n                // Output format: [Textarea label=\"Label\" placeholder=\"Placeholder\"] [textarea_1]\n                let displayText = `[Textarea`; // Changed from \"Text area\" for consistency\n                 if (labelText) displayText += ` label=\"${labelText}\"`;\n                 else if (placeholder) displayText += ` placeholder=\"${placeholder}\"`;\n                 else if (name) displayText += ` name=\"${name}\"`;\n                // if (value) displayText += ` value=\"${value}\"`; // Optional: include current value\n                displayText += `]`;\n\n                elementOutputPrefix = displayText;\n                elementOutputSuffix = ` [${elementId}] `;\n                processChildren = false; // textContent/value is the primary info\n            }\n            // Paragraphs\n             else if (tagName === 'p') {\n                // Process children, add paragraph breaks\n                elementContent = Array.from(element.childNodes).map(processNode).join('');\n                const trimmedContent = elementContent.trim();\n                if (trimmedContent && trimmedContent.length > 10 && !processedTextContent.has(trimmedContent)) { // Add length check and deduplication\n                     // Optionally add ID for long/unique paragraphs\n                     // elementId = `p_${elementCounter++}`;\n                     // elements[elementId] = { type: 'paragraph', text: element.textContent?.trim() || '' };\n                     // references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                     // elementOutputSuffix = ` [${elementId}]`;\n                     processedTextContent.add(trimmedContent);\n                     return `${trimmedContent}\\n\\n`; // Add paragraph break\n                 } else if (trimmedContent) {\n                     return `${trimmedContent}\\n\\n`; // Still add breaks for shorter paragraphs if not empty\n                 } else {\n                     return ''; // Skip empty paragraphs\n                 }\n            }\n            // List Items\n             else if (tagName === 'li') {\n                // Process children, add list marker\n                elementContent = Array.from(element.childNodes).map(processNode).join('');\n                 const trimmedContent = elementContent.trim();\n                 if (trimmedContent) {\n                     // Optionally add ID\n                     // elementId = `li_${elementCounter++}`;\n                     // elements[elementId] = { type: 'list-item', text: element.textContent?.trim() || '' };\n                     // references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                     // elementOutputSuffix = ` [${elementId}]`;\n                     return `• ${trimmedContent}\\n`; // Add bullet and newline\n                 } else {\n                     return ''; // Skip empty list items\n                 }\n            }\n             // Unordered/Ordered Lists\n             else if (tagName === 'ul' || tagName === 'ol') {\n                 elementContent = Array.from(element.childNodes).map(processNode).join('');\n                 // Add extra newline after the list for spacing\n                 return elementContent.trim() ? `${elementContent.trim()}\\n\\n` : '';\n             }\n            // Code Blocks (PRE/CODE)\n             else if (tagName === 'pre' || tagName === 'code') {\n                if (includeCodeBlocks) {\n                     elementId = `${tagName}_${elementCounter++}`;\n                     const text = element.textContent || ''; // Get raw text content\n                     elements[elementId] = { type: tagName, text: text.trim() };\n                     references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n\n                     // Output format: ```language\\n code \\n``` [code_1]\n                     const langClass = element.className.match(/language-(\\w+)/);\n                     const lang = langClass ? langClass[1] : '';\n                     elementOutputPrefix = `\\`\\`\\`${lang}\\n${text.trim()}\\n\\`\\`\\``;\n                     elementOutputSuffix = ` [${elementId}]\\n\\n`;\n                     processChildren = false; // Don't process children of code blocks\n                 } else {\n                     return '[Code Block]\\n\\n'; // Placeholder if not including content\n                 }\n            }\n             // Labels (often contain text for inputs) - process their content\n             else if (tagName === 'label') {\n                 // Process children normally, the text will be picked up by findLabelText if needed\n                 processChildren = true;\n             }\n            // Images\n             else if (tagName === 'img') {\n                 const alt = element.getAttribute('alt')?.trim();\n                 const src = element.getAttribute('src');\n                 if (alt) {\n                     elementId = `img_${elementCounter++}`;\n                     elements[elementId] = { type: 'image', text: alt, attributes: { alt: alt, ...(src && {src: src}) } };\n                     references[elementId] = { selector: createSelector(element), class: element.getAttribute('class') || undefined };\n                     elementOutputPrefix = `[Image: ${alt}]`;\n                     elementOutputSuffix = ` [${elementId}] `;\n                 }\n                 // Maybe return empty string if no alt text? Or a placeholder?\n                 // else { return '[Image] '; }\n                 processChildren = false; // Images don't have children\n             }\n\n            // --- Default Handling for Other Elements (div, span, etc.) ---\n            if (processChildren) {\n                elementContent = Array.from(element.childNodes).map(processNode).join('');\n            }\n\n            // Add prefix/suffix if an ID was generated for this element\n            return `${elementOutputPrefix}${elementContent}${elementOutputSuffix}`;\n        };\n\n        // Helper function to find text associated with an input/textarea/select\n        const findLabelText = (element: Element): string | null => {\n            // 1. Check for aria-label or aria-labelledby\n             const ariaLabel = element.getAttribute('aria-label');\n             if (ariaLabel) return ariaLabel;\n             const ariaLabelledBy = element.getAttribute('aria-labelledby');\n             if (ariaLabelledBy) {\n                 const labelElement = tempElement.querySelector(`#${CSS.escape(ariaLabelledBy)}`);\n                 if (labelElement) return labelElement.textContent?.trim() || null;\n             }\n\n            // 2. Look for a <label> element pointing to this element's ID\n            if (element.id) {\n                const label = tempElement.querySelector(`label[for=\"${CSS.escape(element.id)}\"]`);\n                if (label) {\n                    return label.textContent?.trim() || null;\n                }\n            }\n\n            // 3. Look for a <label> element wrapping this element\n            const parentLabel = element.closest('label');\n            if (parentLabel) {\n                // Get text content of the label, excluding the input/select/textarea itself\n                let labelText = '';\n                 Array.from(parentLabel.childNodes).forEach(child => {\n                     if (child !== element) {\n                         labelText += child.textContent || '';\n                     }\n                 });\n                 return labelText.trim() || null;\n             }\n\n             // 4. Check for a sibling label immediately before (common pattern without 'for')\n             let prevSibling = element.previousElementSibling;\n             while(prevSibling && prevSibling.nodeType !== Node.ELEMENT_NODE) {\n                 prevSibling = prevSibling.previousElementSibling;\n             }\n             if (prevSibling && prevSibling.tagName.toLowerCase() === 'label') {\n                 return prevSibling.textContent?.trim() || null;\n             }\n\n             // 5. Look within common parent structure like <div class=\"q\"> <label>...</label> <input/> </div>\n             const commonParent = element.closest('.q, .form-group, .input-group'); // Add common form group classes\n             if (commonParent) {\n                 const label = commonParent.querySelector('label');\n                 if (label && !label.hasAttribute('for')) { // If label doesn't have 'for', assume it's for this input\n                     return label.textContent?.trim() || null;\n                 }\n             }\n\n\n            return null; // No label found\n        };\n\n\n        // Start processing from the body or the root temp element\n        const body = tempElement.querySelector('body') || tempElement;\n        let content = processNode(body);\n\n        // --- Final Cleanup ---\n        content = content\n            .replace(/\\s+\\n/g, '\\n')      // Remove spaces before newlines\n            .replace(/\\n\\s+/g, '\\n')      // Remove spaces after newlines (start of line)\n            .replace(/\\n{3,}/g, '\\n\\n')   // Normalize multiple newlines to max two\n            .replace(/[ \\t]{2,}/g, ' ')     // Replace multiple spaces/tabs with a single space\n            .replace(/^ +/gm, '')        // Remove leading spaces on each line\n            .trim();                       // Trim leading/trailing whitespace from the whole string\n\n        // Optional: Apply final deduplication if needed (can be aggressive)\n        // content = this.deduplicateFinalOutput(content);\n\n        // Optional: Further clean up potentially redundant/nested IDs if they cause issues\n        // This might remove valid nested IDs, use with caution\n        // content = content.replace(/(\\[[a-z]+_\\d+\\])\\s*(\\[[a-z]+_\\d+\\])/g, '$2'); // Keep only the inner ID if nested\n        // content = content.replace(/\\n\\s*\\[\\w+_\\d+\\]\\s*\\n/g, '\\n');   // Remove element IDs on their own lines\n\n        return { content, elements, references };\n    }\n}","export function identifyMainContent(cleanedText: string): string {\n    // Split text into paragraphs\n    const paragraphs = cleanedText.split('\\n\\n').filter(p => p.trim());\n    \n    if (paragraphs.length === 0) return cleanedText;\n\n    // Use heuristics to identify main content\n    const mainParagraphs = paragraphs.filter(p => {\n        const words = p.split(/\\s+/).length;\n        return words > 20 && words < 1000; // Reasonable paragraph length\n    });\n\n    return mainParagraphs.length > 0 ? mainParagraphs.join('\\n\\n') : cleanedText;\n}\n\n// TODO: Implement these additional content identification functions\n/*\n- Add semantic structure analysis\n- Add relevance scoring\n- Add content classification\n- Add language detection\n- Add summary generation\n*/\n\nexport interface ContentClassification {\n    type: 'article' | 'product' | 'form' | 'navigation' | 'other';\n    confidence: number;\n    keywords: string[];\n    entities: string[];\n}\n\nexport function classifyContent(content: string): ContentClassification {\n    const words = content.toLowerCase().split(/\\s+/);\n    const wordFreq = new Map<string, number>();\n    \n    // Calculate word frequencies\n    words.forEach(word => {\n        if (word.length > 3) { // Skip short words\n            wordFreq.set(word, (wordFreq.get(word) || 0) + 1);\n        }\n    });\n\n    // Extract keywords (words with high frequency)\n    const keywords = Array.from(wordFreq.entries())\n        .sort((a, b) => b[1] - a[1])\n        .slice(0, 10)\n        .map(([word]) => word);\n\n    // Simple classification based on content patterns\n    const classification = determineContentType(keywords);\n\n    return {\n        ...classification,\n        keywords,\n        entities: extractEntities(content)\n    };\n}\n\nfunction determineContentType(keywords: string[]): Pick<ContentClassification, 'type' | 'confidence'> {\n    const patterns = {\n        article: ['article', 'post', 'blog', 'news', 'story'],\n        product: ['price', 'buy', 'cart', 'shop', 'product'],\n        form: ['submit', 'input', 'form', 'select', 'checkbox'],\n        navigation: ['menu', 'nav', 'link', 'home', 'page']\n    };\n\n    const scores = Object.entries(patterns).map(([type, patterns]) => {\n        const score = patterns.reduce((acc, pattern) => {\n            return acc + (keywords.includes(pattern) ? 1 : 0);\n        }, 0) / patterns.length;\n        return { type, score };\n    });\n\n    const bestMatch = scores.reduce((a, b) => a.score > b.score ? a : b);\n    \n    return {\n        type: bestMatch.score > 0.3 ? bestMatch.type as ContentClassification['type'] : 'other',\n        confidence: bestMatch.score\n    };\n}\n\nfunction extractEntities(content: string): string[] {\n    // Simple named entity recognition\n    const entities: string[] = [];\n    \n    // Find potential proper nouns (words starting with capital letters)\n    const words = content.split(/\\s+/);\n    let currentEntity = '';\n    \n    words.forEach(word => {\n        if (/^[A-Z][a-zA-Z]*$/.test(word)) {\n            currentEntity += currentEntity ? ` ${word}` : word;\n        } else {\n            if (currentEntity) {\n                entities.push(currentEntity);\n                currentEntity = '';\n            }\n        }\n    });\n\n    // Remove duplicates and return\n    return [...new Set(entities)];\n}\n\nexport interface ContentSection {\n    type: 'header' | 'profile' | 'main' | 'navigation' | 'interaction' | 'metadata' | 'other';\n    elements: Element[];\n    content: string;\n    relevanceScore?: number;\n    confidence: number;\n}\n\nexport interface SectionAnalysis {\n    sections: ContentSection[];\n    summary: string;\n    recommendedSections: ContentSection[];\n}\n\n// Add new platform-specific patterns\nexport interface PlatformPatterns {\n    selectors: string[];\n    classPatterns: RegExp[];\n    contentRules: {\n        type: ContentSection['type'];\n        patterns: string[];\n    }[];\n}\n\nconst PLATFORM_PATTERNS: Record<string, PlatformPatterns> = {\n    linkedin: {\n        selectors: [\n            '[data-test-id]',\n            '.profile-section',\n            '.feed-shared-update-v2',\n            '.scaffold-layout__main'\n        ],\n        classPatterns: [\n            /artdeco-card/,\n            /profile-/,\n            /feed-shared/,\n            /scaffold-layout/\n        ],\n        contentRules: [\n            {\n                type: 'profile',\n                patterns: ['connections', 'followers', 'experience', 'education', 'skills']\n            },\n            {\n                type: 'interaction',\n                patterns: ['connect', 'follow', 'message', 'react', 'comment', 'share']\n            }\n        ]\n    },\n    twitter: {\n        selectors: [\n            '[data-testid]',\n            '.tweet',\n            '.profile-timeline',\n            '[role=\"article\"]'\n        ],\n        classPatterns: [\n            /css-\\d+/,\n            /tweet-/,\n            /timeline-/\n        ],\n        contentRules: [\n            {\n                type: 'profile',\n                patterns: ['followers', 'following', 'joined', 'tweets']\n            },\n            {\n                type: 'interaction',\n                patterns: ['reply', 'retweet', 'like', 'share', 'bookmark']\n            }\n        ]\n    },\n    // Generic patterns for any website\n    generic: {\n        selectors: [\n            'main',\n            'header',\n            'nav',\n            'article',\n            'aside',\n            'section',\n            '[role=\"main\"]',\n            '[role=\"navigation\"]',\n            '[role=\"complementary\"]'\n        ],\n        classPatterns: [\n            /main/i,\n            /header/i,\n            /content/i,\n            /navigation/i\n        ],\n        contentRules: [\n            {\n                type: 'main',\n                patterns: ['article', 'post', 'content', 'story']\n            },\n            {\n                type: 'navigation',\n                patterns: ['menu', 'nav', 'links', 'sidebar']\n            }\n        ]\n    }\n};\n\nexport class ContentSectionAnalyzer {\n    private platform: string = 'generic';\n    private patterns: PlatformPatterns;\n\n    constructor() {\n        // Start with generic patterns\n        this.patterns = PLATFORM_PATTERNS.generic;\n    }\n\n    /**\n     * Detect the platform and set appropriate patterns\n     */\n    private detectPlatform(): void {\n        const url = window.location.hostname;\n        \n        if (url.includes('linkedin')) {\n            this.platform = 'linkedin';\n        } else if (url.includes('twitter')) {\n            this.platform = 'twitter';\n        } else {\n            this.platform = 'generic';\n        }\n        \n        this.patterns = {\n            ...PLATFORM_PATTERNS.generic,\n            ...PLATFORM_PATTERNS[this.platform]\n        };\n    }\n\n    analyzeSections(rootElement: Element, task?: string): SectionAnalysis {\n        // Detect platform first\n        this.detectPlatform();\n        \n        // Step 1: Initial section grouping\n        const sections = this.groupIntoSections(rootElement);\n        \n        // Step 2: Analyze and score sections\n        const analyzedSections = this.analyzeSectionRelevance(sections, task);\n        \n        // Step 3: Generate summary and recommendations\n        return {\n            sections: analyzedSections,\n            summary: this.generateSectionSummary(analyzedSections),\n            recommendedSections: this.getRecommendedSections(analyzedSections)\n        };\n    }\n\n    private groupIntoSections(rootElement: Element): ContentSection[] {\n        const sections: ContentSection[] = [];\n        \n        // Helper to determine if elements are related\n        const areElementsRelated = (el1: Element, el2: Element): boolean => {\n            // Check proximity in DOM\n            const distance = this.calculateDOMDistance(el1, el2);\n            if (distance > 3) return false;\n            \n            // Check visual proximity (if elements have position data)\n            const visuallyClose = this.areElementsVisuallyClose(el1, el2);\n            if (!visuallyClose) return false;\n            \n            // Check semantic relationship\n            return this.areElementsSemanticallyRelated(el1, el2);\n        };\n\n        // Start with landmark elements\n        const landmarks = rootElement.querySelectorAll('main, header, nav, article, aside, section');\n        landmarks.forEach(landmark => {\n            const type = this.determineSectionType(landmark);\n            sections.push({\n                type,\n                elements: [landmark],\n                content: landmark.textContent || '',\n                confidence: 0.9\n            });\n        });\n\n        // Group remaining elements\n        const ungroupedElements = Array.from(rootElement.querySelectorAll('*'))\n            .filter(el => !this.isElementInSections(el, sections));\n\n        let currentGroup: Element[] = [];\n        let currentType: ContentSection['type'] = 'other';\n\n        ungroupedElements.forEach(element => {\n            if (currentGroup.length === 0) {\n                currentGroup.push(element);\n                currentType = this.determineSectionType(element);\n            } else {\n                const lastElement = currentGroup[currentGroup.length - 1];\n                if (areElementsRelated(lastElement, element)) {\n                    currentGroup.push(element);\n                } else {\n                    // Create new section from current group\n                    sections.push({\n                        type: currentType,\n                        elements: [...currentGroup],\n                        content: currentGroup.map(el => el.textContent).join(' '),\n                        confidence: 0.7\n                    });\n                    currentGroup = [element];\n                    currentType = this.determineSectionType(element);\n                }\n            }\n        });\n\n        // Add any remaining elements\n        if (currentGroup.length > 0) {\n            sections.push({\n                type: currentType,\n                elements: currentGroup,\n                content: currentGroup.map(el => el.textContent).join(' '),\n                confidence: 0.7\n            });\n        }\n\n        return sections;\n    }\n\n    private analyzeSectionRelevance(sections: ContentSection[], task?: string): ContentSection[] {\n        return sections.map(section => {\n            const relevanceScore = this.calculateRelevanceScore(section, task);\n            return {\n                ...section,\n                relevanceScore\n            };\n        });\n    }\n\n    private calculateRelevanceScore(section: ContentSection, task?: string): number {\n        let score = 0;\n\n        // Base score from content quality\n        score += this.evaluateContentQuality(section.content);\n\n        // Adjust based on section type\n        score += this.getTypeRelevanceScore(section.type);\n\n        // If task is provided, evaluate relevance to task\n        if (task) {\n            score += this.evaluateTaskRelevance(section.content, task);\n        }\n\n        // Normalize score to 0-1 range\n        return Math.min(Math.max(score / 3, 0), 1);\n    }\n\n    private evaluateContentQuality(content: string): number {\n        let score = 0;\n        \n        // Check content length\n        const words = content.split(/\\s+/).length;\n        if (words > 10 && words < 1000) score += 0.3;\n        \n        // Check for meaningful content\n        if (!/^\\s*$/.test(content)) score += 0.2;\n        \n        // Check for structured content\n        if (content.includes('\\n')) score += 0.2;\n        \n        // Check for interactive elements\n        if (/button|link|input/i.test(content)) score += 0.3;\n        \n        return score;\n    }\n\n    private getTypeRelevanceScore(type: ContentSection['type']): number {\n        const typeScores: Record<ContentSection['type'], number> = {\n            header: 0.7,\n            profile: 0.8,\n            main: 1.0,\n            navigation: 0.4,\n            interaction: 0.6,\n            metadata: 0.3,\n            other: 0.2\n        };\n        \n        return typeScores[type];\n    }\n\n    private evaluateTaskRelevance(content: string, task: string): number {\n        // Convert content and task to lowercase for comparison\n        const normalizedContent = content.toLowerCase();\n        const normalizedTask = task.toLowerCase();\n\n        // Extract keywords from task\n        const taskKeywords = normalizedTask\n            .split(/\\s+/)\n            .filter(word => word.length > 3);\n\n        // Calculate keyword matches\n        const matchingKeywords = taskKeywords.filter(keyword => \n            normalizedContent.includes(keyword)\n        );\n\n        return matchingKeywords.length / taskKeywords.length;\n    }\n\n    private determineSectionType(element: Element): ContentSection['type'] {\n        const tagName = element.tagName.toLowerCase();\n        const role = element.getAttribute('role');\n        const className = element.className;\n        const textContent = element.textContent?.toLowerCase() || '';\n\n        // Check platform-specific patterns first\n        for (const rule of this.patterns.contentRules) {\n            if (rule.patterns.some(pattern => \n                textContent.includes(pattern) || \n                className.toLowerCase().includes(pattern)\n            )) {\n                return rule.type;\n            }\n        }\n\n        // Check for platform-specific selectors\n        if (this.patterns.selectors.some(selector => element.matches(selector))) {\n            // Determine type based on context and content\n            return this.inferTypeFromContext(element);\n        }\n\n        // Fall back to generic type detection\n        if (tagName === 'header' || /header|banner/i.test(className)) {\n            return 'header';\n        }\n        if (/profile|user-info/i.test(className)) {\n            return 'profile';\n        }\n        if (tagName === 'main' || role === 'main' || /main-content/i.test(className)) {\n            return 'main';\n        }\n        if (tagName === 'nav' || role === 'navigation') {\n            return 'navigation';\n        }\n        if (/button|form|input/i.test(tagName)) {\n            return 'interaction';\n        }\n        if (/metadata|info|details/i.test(className)) {\n            return 'metadata';\n        }\n        \n        return 'other';\n    }\n\n    private inferTypeFromContext(element: Element): ContentSection['type'] {\n        const context = {\n            hasInteractiveElements: element.querySelectorAll('button, a, input, textarea').length > 0,\n            hasImages: element.querySelectorAll('img').length > 0,\n            textLength: element.textContent?.length || 0,\n            isNearHeader: this.isNearElementType(element, 'header'),\n            isNearNav: this.isNearElementType(element, 'nav'),\n            hasStructuredData: element.querySelectorAll('ul, ol, table').length > 0\n        };\n\n        // Use context to infer section type\n        if (context.hasInteractiveElements && context.textLength < 200) {\n            return 'interaction';\n        }\n        if (context.hasImages && context.textLength > 500) {\n            return 'main';\n        }\n        if (context.hasStructuredData && context.isNearNav) {\n            return 'navigation';\n        }\n        if (context.isNearHeader && context.textLength < 300) {\n            return 'metadata';\n        }\n\n        return 'other';\n    }\n\n    private isNearElementType(element: Element, type: string): boolean {\n        const distance = 3; // Check 3 elements up and down\n        let current = element;\n        \n        // Check previous siblings\n        for (let i = 0; i < distance && current.previousElementSibling; i++) {\n            current = current.previousElementSibling;\n            if (current.tagName.toLowerCase() === type) return true;\n        }\n        \n        // Check next siblings\n        current = element;\n        for (let i = 0; i < distance && current.nextElementSibling; i++) {\n            current = current.nextElementSibling;\n            if (current.tagName.toLowerCase() === type) return true;\n        }\n        \n        return false;\n    }\n\n    private calculateDOMDistance(el1: Element, el2: Element): number {\n        const path1 = this.getPathToRoot(el1);\n        const path2 = this.getPathToRoot(el2);\n        \n        // Find common ancestor\n        let commonAncestorIndex = 0;\n        const maxLength = Math.min(path1.length, path2.length);\n        \n        while (commonAncestorIndex < maxLength && \n               path1[commonAncestorIndex] === path2[commonAncestorIndex]) {\n            commonAncestorIndex++;\n        }\n        \n        return (path1.length - commonAncestorIndex) + \n               (path2.length - commonAncestorIndex);\n    }\n\n    private getPathToRoot(element: Element): Element[] {\n        const path: Element[] = [];\n        let current: Element | null = element;\n        \n        while (current) {\n            path.unshift(current);\n            current = current.parentElement;\n        }\n        \n        return path;\n    }\n\n    private areElementsVisuallyClose(el1: Element, el2: Element): boolean {\n        const rect1 = el1.getBoundingClientRect();\n        const rect2 = el2.getBoundingClientRect();\n        \n        // Calculate distance between elements\n        const horizontalDistance = Math.abs(rect1.left - rect2.left);\n        const verticalDistance = Math.abs(rect1.top - rect2.top);\n        \n        // Consider elements close if they're within 100px of each other\n        return horizontalDistance < 100 && verticalDistance < 100;\n    }\n\n    private areElementsSemanticallyRelated(el1: Element, el2: Element): boolean {\n        // Add platform-specific class pattern checking\n        const matchesPatterns = this.patterns.classPatterns.some(pattern => {\n            const el1Match = Array.from(el1.classList).some(c => pattern.test(c));\n            const el2Match = Array.from(el2.classList).some(c => pattern.test(c));\n            return el1Match && el2Match;\n        });\n\n        if (matchesPatterns) return true;\n\n        // Fallback to existing semantic relationship checks\n        return this.areElementsSemanticallyRelated(el1, el2);\n    }\n\n    private isElementInSections(element: Element, sections: ContentSection[]): boolean {\n        return sections.some(section => \n            section.elements.some(el => el.contains(element))\n        );\n    }\n\n    private generateSectionSummary(sections: ContentSection[]): string {\n        const relevantSections = sections\n            .filter(s => (s.relevanceScore || 0) > 0.5)\n            .sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0));\n\n        return relevantSections\n            .map(section => `${section.type.toUpperCase()}: ${\n                section.content.substring(0, 100)}${\n                section.content.length > 100 ? '...' : ''\n            } (Relevance: ${(section.relevanceScore || 0).toFixed(2)})`)\n            .join('\\n\\n');\n    }\n\n    private getRecommendedSections(sections: ContentSection[]): ContentSection[] {\n        return sections\n            .filter(s => (s.relevanceScore || 0) > 0.7)\n            .sort((a, b) => (b.relevanceScore || 0) - (a.relevanceScore || 0));\n    }\n}","export interface BrowserAgentAction {\n    type: 'click' | 'scroll' | 'navigate' | 'extract' | 'read' | 'wait' | \n          'think' | 'analyze' | 'classify' | 'summarize';\n    target?: string;\n    value?: any;\n    taskType?: AgentModelConfig['taskType'];\n}\n\nexport interface PageMetadata {\n    title: string;\n    url: string;\n    description: string;\n    keywords: string;\n    timestamp: string;\n}\n\nexport interface RetryConfig {\n    maxRetries: number;\n    delay: number;\n    backoffFactor: number;\n}\n\nexport class ActionError extends Error {\n    constructor(\n        public action: BrowserAgentAction,\n        message: string\n    ) {\n        super(`Failed to execute ${action.type}: ${message}`);\n        this.name = 'ActionError';\n    }\n}\n\nexport interface AgentState {\n    currentUrl: string;\n    lastAction: BrowserAgentAction | null;\n    actionHistory: BrowserAgentAction[];\n    errors: ActionError[];\n}\n\nexport interface AgentModelConfig {\n    taskType: 'navigation' | 'analysis' | 'extraction' | 'decision' | 'conversation';\n    modelId: string;\n    options?: Record<string, unknown>;\n}\n\nexport interface AgentConfig {\n    models: {\n        [key in AgentModelConfig['taskType']]?: AgentModelConfig;\n    };\n    defaultModel?: string;\n}\n","import { HTMLCleaner } from './html-cleaner';\nimport { identifyMainContent } from './content-identifier';\nimport { PageMetadata, ActionError, RetryConfig, BrowserAgentAction, AgentConfig, AgentModelConfig } from '@/core/agent/types';\nimport { BrowserAI } from '@/core/llm';\n\n// CURRENTLY WIP\n\nexport class BrowserAgent {\n    private currentUrl: string;\n    private htmlCleaner: HTMLCleaner;\n    private actionHistory: BrowserAgentAction[] = [];\n    private retryConfig: RetryConfig = {\n        maxRetries: 3,\n        delay: 1000,\n        backoffFactor: 1.5\n    };\n    private browserAI: BrowserAI;\n    private config: AgentConfig;\n\n    constructor(config: AgentConfig) {\n        this.currentUrl = window.location.href;\n        this.htmlCleaner = new HTMLCleaner();\n        this.browserAI = new BrowserAI();\n        this.config = config;\n        this.initializeModels();\n    }\n\n    private async initializeModels() {\n        // Load default model if specified\n        if (this.config.defaultModel) {\n            await this.browserAI.loadModel(this.config.defaultModel);\n        }\n    }\n\n    private async getModelForTask(taskType: AgentModelConfig['taskType']): Promise<void> {\n        const modelConfig = this.config.models[taskType];\n        if (!modelConfig) {\n            if (!this.config.defaultModel) {\n                throw new Error(`No model configured for task type ${taskType}`);\n            }\n            return;\n        }\n\n        // Load the specific model for this task if it's different from current\n        if (this.browserAI.currentModel?.modelName !== modelConfig.modelId) {\n            await this.browserAI.loadModel(modelConfig.modelId, modelConfig.options);\n        }\n    }\n\n    async executeAction(action: BrowserAgentAction): Promise<any> {\n        try {\n            this.actionHistory.push(action);\n            return await this.executeWithRetry(() => this.performAction(action));\n        } catch (error: unknown) {\n            if (error instanceof Error) {\n                throw new ActionError(action, error.message);\n            }\n            throw new ActionError(action, String(error));\n        }\n    }\n\n    private async executeWithRetry(fn: () => Promise<any>, attempt = 1): Promise<any> {\n        try {\n            return await fn();\n        } catch (error) {\n            if (attempt >= this.retryConfig.maxRetries) {\n                throw error;\n            }\n            \n            const delay = this.retryConfig.delay * Math.pow(this.retryConfig.backoffFactor, attempt - 1);\n            await this.wait(delay);\n            return this.executeWithRetry(fn, attempt + 1);\n        }\n    }\n\n    private async performAction(action: BrowserAgentAction): Promise<any> {\n        this.validateAction(action);\n        \n        // If action requires AI, ensure correct model is loaded\n        if (action.taskType) {\n            await this.getModelForTask(action.taskType);\n        }\n        \n        switch (action.type) {\n            case 'click':\n                return this.clickElement(action.target as string);\n            case 'scroll':\n                return this.scroll(action.value);\n            case 'navigate':\n                return this.navigate(action.target as string);\n            case 'extract':\n                return this.extractContent(action.target as string);\n            case 'read':\n                return this.readPageContent();\n            case 'wait':\n                return this.wait(action.value);\n            case 'think':\n                return this.makeDecision(action.value);\n            case 'analyze':\n                return this.analyzeContent(action.value);\n            case 'classify':\n                return this.classifyContent(action.value);\n            case 'summarize':\n                return this.summarizeContent(action.value);\n        }\n    }\n\n    private validateAction(action: BrowserAgentAction): void {\n        switch (action.type) {\n            case 'click':\n            case 'extract':\n                if (!action.target) {\n                    throw new Error(`${action.type} action requires a target selector`);\n                }\n                break;\n            case 'scroll':\n                if (!action.value?.direction || !action.value?.amount) {\n                    throw new Error('Scroll action requires direction and amount');\n                }\n                break;\n            case 'navigate':\n                if (!action.target || !action.target.startsWith('http')) {\n                    throw new Error('Navigate action requires a valid URL');\n                }\n                break;\n        }\n    }\n\n    private async clickElement(selector: string): Promise<boolean> {\n        const element = document.querySelector(selector);\n        if (element && element instanceof HTMLElement) {\n            element.click();\n            return true;\n        }\n        return false;\n    }\n\n    private async scroll(options: { direction: 'up' | 'down', amount: number }): Promise<void> {\n        window.scrollBy({\n            top: options.direction === 'down' ? options.amount : -options.amount,\n            behavior: 'smooth'\n        });\n    }\n\n    private async navigate(url: string): Promise<void> {\n        window.location.href = url;\n    }\n\n    private async extractContent(selector: string): Promise<string> {\n        const element = document.querySelector(selector);\n        return element ? this.htmlCleaner.clean(element.innerHTML) : '';\n    }\n\n    private async readPageContent(): Promise<{\n        mainContent: string;\n        semanticContent: string;\n        metadata: PageMetadata;\n    }> {\n        const html = document.documentElement.innerHTML;\n        return {\n            mainContent: await this.getMainContent(html),\n            semanticContent: this.htmlCleaner.cleanSemantic(html),\n            metadata: this.extractMetadata()\n        };\n    }\n\n    private async wait(ms: number): Promise<void> {\n        return new Promise(resolve => setTimeout(resolve, ms));\n    }\n\n    private async getMainContent(html: string): Promise<string> {\n        const cleanedText = this.htmlCleaner.clean(html);\n        return identifyMainContent(cleanedText);\n    }\n\n    private extractMetadata(): PageMetadata {\n        return {\n            title: document.title,\n            url: this.currentUrl,\n            description: this.getMetaContent('description'),\n            keywords: this.getMetaContent('keywords'),\n            timestamp: new Date().toISOString()\n        };\n    }\n\n    private getMetaContent(name: string): string {\n        const meta = document.querySelector(`meta[name=\"${name}\"]`);\n        return meta ? meta.getAttribute('content') || '' : '';\n    }\n\n    private async makeDecision(context: string): Promise<{\n        nextAction: BrowserAgentAction;\n        reasoning: string;\n    }> {\n        await this.getModelForTask('decision');\n        \n        const prompt = `\n        Context: ${context}\n        Current URL: ${this.currentUrl}\n        \n        Analyze the context and decide the next action. \n        Respond in JSON format with:\n        {\n            \"nextAction\": {\n                \"type\": \"...\",\n                \"target\": \"...\",\n                \"value\": \"...\"\n            },\n            \"reasoning\": \"...\"\n        }\n        `;\n\n        const response = await this.browserAI.generateText(prompt);\n        return JSON.parse(response as string);\n    }\n\n    private async analyzeContent(content: string): Promise<{\n        summary: string;\n        entities: string[];\n        sentiment: string;\n        topics: string[];\n    }> {\n        await this.getModelForTask('analysis');\n        \n        const prompt = `\n        Analyze this content:\n        ${content}\n        \n        Provide a detailed analysis including summary, entities, sentiment, and topics.\n        Respond in JSON format.\n        `;\n\n        const response = await this.browserAI.generateText(prompt);\n        return JSON.parse(response as string);\n    }\n\n    private async classifyContent(content: string): Promise<{\n        type: string;\n        confidence: number;\n        categories: string[];\n    }> {\n        await this.getModelForTask('analysis');\n        const response = await this.browserAI.generateText(`\n            Classify this content: ${content}\n            Respond in JSON format with type, confidence, and categories.\n        `);\n        return JSON.parse(response as string);\n    }\n\n    private async summarizeContent(content: string): Promise<{\n        summary: string;\n        keyPoints: string[];\n    }> {\n        await this.getModelForTask('analysis');\n        const response = await this.browserAI.generateText(`\n            Summarize this content: ${content}\n            Respond in JSON format with summary and key points.\n        `);\n        return JSON.parse(response as string);\n    }\n\n    // Example usage with different models\n    async performTask(goal: string): Promise<void> {\n        // Read the page\n        const content = await this.executeAction({ \n            type: 'read' \n        });\n\n        // Analyze content using analysis model\n        const analysis = await this.executeAction({ \n            type: 'analyze',\n            value: content.mainContent,\n            taskType: 'analysis'\n        });\n\n        // Make decision using decision model\n        const decision = await this.executeAction({\n            type: 'think',\n            value: `Goal: ${goal}\\nAnalysis: ${JSON.stringify(analysis)}`,\n            taskType: 'decision'\n        });\n\n        // Execute the decided action\n        await this.executeAction(decision.nextAction);\n    }\n\n    getActionHistory(): BrowserAgentAction[] {\n        return [...this.actionHistory];\n    }\n}","/**\n * DOM Structure Analyzer\n * A TypeScript library for identifying semantic sections of webpages\n */\n\n// Types for our library\nexport type SectionType = \n  | 'navigation' \n  | 'header' \n  | 'footer' \n  | 'sidebar' \n  | 'main-content' \n  | 'article'\n  | 'comments'\n  | 'search'\n  | 'social-links'\n  | 'advertisement'\n  | 'form'\n  | 'unknown';\n\nexport interface AnalysisResult {\n  element: HTMLElement;\n  type: SectionType;\n  confidence: number;\n  highlightColor?: string;\n}\n\nexport interface AnalyzerOptions {\n  highlightColors?: Record<SectionType, string>;\n  minimumConfidence?: number;\n  enabledAnalyzers?: Array<keyof typeof analyzers>;\n}\n\n// Default options\nconst DEFAULT_OPTIONS: AnalyzerOptions = {\n  highlightColors: {\n    'navigation': 'rgba(255, 0, 0, 0.2)',\n    'header': 'rgba(0, 255, 0, 0.2)',\n    'footer': 'rgba(0, 0, 255, 0.2)',\n    'sidebar': 'rgba(255, 255, 0, 0.2)',\n    'main-content': 'rgba(255, 0, 255, 0.2)',\n    'article': 'rgba(0, 255, 255, 0.2)',\n    'comments': 'rgba(128, 0, 128, 0.2)',\n    'search': 'rgba(255, 165, 0, 0.2)',\n    'social-links': 'rgba(0, 128, 128, 0.2)',\n    'advertisement': 'rgba(128, 128, 0, 0.2)',\n    'form': 'rgba(128, 0, 0, 0.2)',\n    'unknown': 'rgba(128, 128, 128, 0.2)'\n  },\n  minimumConfidence: 0.6,\n  enabledAnalyzers: ['semantic', 'classId', 'position', 'content', 'aria']\n};\n\n/**\n * Main class for DOM Structure Analysis\n */\nexport class DOMStructureAnalyzer {\n  private options: AnalyzerOptions;\n  private results: AnalysisResult[] = [];\n  private highlightElements: HTMLElement[] = [];\n\n  constructor(options: Partial<AnalyzerOptions> = {}) {\n    this.options = { ...DEFAULT_OPTIONS, ...options };\n  }\n\n  /**\n   * Analyze the DOM to identify sections\n   */\n  public analyze(root: HTMLElement = document.body): AnalysisResult[] {\n    this.results = [];\n    this.removeHighlights();\n\n    // Get all elements that might be structural sections\n    const potentialSections = this.getPotentialSections(root);\n    \n    // Analyze each potential section\n    potentialSections.forEach(element => {\n      const elementResults: Record<SectionType, number> = {\n        'navigation': 0,\n        'header': 0,\n        'footer': 0,\n        'sidebar': 0,\n        'main-content': 0,\n        'article': 0,\n        'comments': 0,\n        'search': 0,\n        'social-links': 0,\n        'advertisement': 0,\n        'form': 0,\n        'unknown': 0\n      };\n\n      // Run enabled analyzers\n      this.options.enabledAnalyzers?.forEach(analyzerName => {\n        const analyzerResults = analyzers[analyzerName](element);\n        \n        // Combine results\n        Object.keys(analyzerResults).forEach(type => {\n          elementResults[type as SectionType] += analyzerResults[type as SectionType];\n        });\n      });\n\n      // Normalize scores to get confidence levels\n      let totalScore = Object.values(elementResults).reduce((sum, score) => sum + score, 0);\n      if (totalScore === 0) {\n        elementResults.unknown = 1;\n        totalScore = 1;\n      }\n\n      // Find the section type with highest confidence\n      let highestType: SectionType = 'unknown';\n      let highestConfidence = 0;\n\n      (Object.keys(elementResults) as SectionType[]).forEach(type => {\n        const confidence = elementResults[type] / totalScore;\n        if (confidence > highestConfidence) {\n          highestConfidence = confidence;\n          highestType = type;\n        }\n      });\n\n      // Add to results if confidence meets minimum threshold\n      if (highestConfidence >= (this.options.minimumConfidence || 0.6)) {\n        this.results.push({\n          element,\n          type: highestType,\n          confidence: highestConfidence,\n          highlightColor: this.options.highlightColors?.[highestType]\n        });\n      }\n    });\n\n    return this.results;\n  }\n\n  /**\n   * Highlight identified sections on the page\n   */\n  public highlight(): void {\n    this.removeHighlights();\n\n    this.results.forEach(result => {\n      const highlightEl = document.createElement('div');\n      highlightEl.classList.add('dom-analyzer-highlight');\n      \n      // Set position and dimensions\n      const rect = result.element.getBoundingClientRect();\n      const scrollX = window.scrollX || document.documentElement.scrollLeft;\n      const scrollY = window.scrollY || document.documentElement.scrollTop;\n      \n      Object.assign(highlightEl.style, {\n        position: 'absolute',\n        top: `${rect.top + scrollY}px`,\n        left: `${rect.left + scrollX}px`,\n        width: `${rect.width}px`,\n        height: `${rect.height}px`,\n        backgroundColor: result.highlightColor || 'rgba(128, 128, 128, 0.2)',\n        zIndex: '10000',\n        pointerEvents: 'none',\n        border: '2px solid rgba(0, 0, 0, 0.5)',\n        borderRadius: '4px',\n        boxSizing: 'border-box'\n      });\n\n      // Add a label\n      const label = document.createElement('div');\n      Object.assign(label.style, {\n        position: 'absolute',\n        top: '0',\n        left: '0',\n        backgroundColor: 'rgba(0, 0, 0, 0.7)',\n        color: 'white',\n        padding: '2px 6px',\n        fontSize: '12px',\n        borderRadius: '2px',\n        pointerEvents: 'none'\n      });\n      label.textContent = `${result.type} (${Math.round(result.confidence * 100)}%)`;\n      highlightEl.appendChild(label);\n\n      document.body.appendChild(highlightEl);\n      this.highlightElements.push(highlightEl);\n    });\n  }\n\n  /**\n   * Remove all highlights\n   */\n  public removeHighlights(): void {\n    this.highlightElements.forEach(el => {\n      if (el.parentNode) {\n        el.parentNode.removeChild(el);\n      }\n    });\n    this.highlightElements = [];\n  }\n\n  /**\n   * Get section mapping (for use in other applications)\n   */\n  public getSectionMap(): Record<SectionType, HTMLElement[]> {\n    const map: Record<SectionType, HTMLElement[]> = {\n      'navigation': [],\n      'header': [],\n      'footer': [],\n      'sidebar': [],\n      'main-content': [],\n      'article': [],\n      'comments': [],\n      'search': [],\n      'social-links': [],\n      'advertisement': [],\n      'form': [],\n      'unknown': []\n    };\n\n    this.results.forEach(result => {\n      map[result.type].push(result.element);\n    });\n\n    return map;\n  }\n\n  /**\n   * Get potential DOM sections for analysis\n   */\n  private getPotentialSections(root: HTMLElement): HTMLElement[] {\n    // First look for semantic elements\n    const semanticSelectors = [\n      'nav', 'header', 'footer', 'aside', 'main', 'article', \n      'section', 'form', 'div.sidebar', 'div.main', 'div.content',\n      'div.navigation', 'div.menu', 'div.header', 'div.footer',\n      '[role=\"navigation\"]', '[role=\"banner\"]', '[role=\"contentinfo\"]',\n      '[role=\"complementary\"]', '[role=\"main\"]', '[role=\"search\"]'\n    ];\n\n    // Get all matching elements\n    const elements = Array.from(\n      root.querySelectorAll(semanticSelectors.join(', '))\n    ) as HTMLElement[];\n\n    // Include the root if it's a potential section itself\n    if (semanticSelectors.some(selector => \n      root.matches(selector) || \n      (root.id && root.id.match(/(nav|header|footer|sidebar|content|main)/i)) ||\n      (root.className && root.className.match(/(nav|header|footer|sidebar|content|main)/i))\n    )) {\n      elements.unshift(root);\n    }\n\n    // Filter out elements that are too small or are nested within already detected elements\n    return this.filterNestedElements(elements);\n  }\n\n  /**\n   * Filter out nested elements to prevent duplicate highlighting\n   */\n  private filterNestedElements(elements: HTMLElement[]): HTMLElement[] {\n    // Sort by DOM depth (shallowest first)\n    elements.sort((a, b) => {\n      let depthA = 0, depthB = 0;\n      let node: Node | null = a;\n      while (node) { depthA++; node = node.parentNode; }\n      node = b;\n      while (node) { depthB++; node = node.parentNode; }\n      return depthA - depthB;\n    });\n\n    // Keep track of which elements to include\n    const filtered: HTMLElement[] = [];\n    \n    elements.forEach(element => {\n      // Check if this element is contained within an already included element\n      const isNested = filtered.some(parent => parent.contains(element) && parent !== element);\n      \n      // Only include if not nested and has minimum size\n      if (!isNested && this.hasMinimumSize(element)) {\n        filtered.push(element);\n      }\n    });\n\n    return filtered;\n  }\n\n  /**\n   * Check if an element has minimum size to be considered a section\n   */\n  private hasMinimumSize(element: HTMLElement): boolean {\n    const rect = element.getBoundingClientRect();\n    return rect.width > 50 && rect.height > 50;\n  }\n}\n\n/**\n * Individual analyzers that assign scores to different section types\n */\nconst analyzers = {\n  /**\n   * Analyzes semantic HTML tags\n   */\n  semantic(element: HTMLElement): Record<SectionType, number> {\n    const scores: Record<SectionType, number> = { } as Record<SectionType, number>;\n    Object.keys(DEFAULT_OPTIONS.highlightColors || {}).forEach(key => {\n      scores[key as SectionType] = 0;\n    });\n\n    const tagName = element.tagName.toLowerCase();\n    \n    switch (tagName) {\n      case 'nav':\n        scores.navigation = 10;\n        break;\n      case 'header':\n        scores.header = 10;\n        break;\n      case 'footer':\n        scores.footer = 10;\n        break;\n      case 'aside':\n        scores.sidebar = 10;\n        break;\n      case 'main':\n        scores['main-content'] = 10;\n        break;\n      case 'article':\n        scores.article = 10;\n        break;\n      case 'form':\n        scores.form = 8;\n        break;\n      case 'section':\n        // Need more info to categorize sections\n        const sectionHeading = element.querySelector('h1, h2, h3, h4, h5, h6');\n        if (sectionHeading) {\n          const headingText = sectionHeading.textContent?.toLowerCase() || '';\n          if (headingText.includes('comment')) scores.comments = 5;\n          else if (headingText.includes('related')) scores['main-content'] = 3;\n          else scores.article = 3;\n        }\n        break;\n    }\n\n    return scores;\n  },\n\n  /**\n   * Analyzes class and ID attributes\n   */\n  classId(element: HTMLElement): Record<SectionType, number> {\n    const scores: Record<SectionType, number> = { } as Record<SectionType, number>;\n    Object.keys(DEFAULT_OPTIONS.highlightColors || {}).forEach(key => {\n      scores[key as SectionType] = 0;\n    });\n\n    const className = element.className.toLowerCase();\n    const id = element.id.toLowerCase();\n    \n    // Navigation indicators\n    if (className.match(/nav|menu|navbar|navigation/) || id.match(/nav|menu|navbar|navigation/)) {\n      scores.navigation += 5;\n    }\n    \n    // Header indicators\n    if (className.match(/header|banner|top/) || id.match(/header|banner|top/)) {\n      scores.header += 5;\n    }\n    \n    // Footer indicators\n    if (className.match(/footer|bottom/) || id.match(/footer|bottom/)) {\n      scores.footer += 5;\n    }\n    \n    // Sidebar indicators\n    if (className.match(/sidebar|side|rail|widget-area/) || id.match(/sidebar|side|rail|widget-area/)) {\n      scores.sidebar += 5;\n    }\n    \n    // Main content indicators\n    if (className.match(/content|main|body|page/) || id.match(/content|main|body|page/)) {\n      scores['main-content'] += 5;\n    }\n    \n    // Article indicators\n    if (className.match(/article|post|entry/) || id.match(/article|post|entry/)) {\n      scores.article += 5;\n    }\n    \n    // Comments indicators\n    if (className.match(/comments|discussion|responses/) || id.match(/comments|discussion|responses/)) {\n      scores.comments += 5;\n    }\n    \n    // Search indicators\n    if (className.match(/search/) || id.match(/search/)) {\n      scores.search += 5;\n    }\n    \n    // Social links indicators\n    if (className.match(/social|share|follow/) || id.match(/social|share|follow/)) {\n      scores['social-links'] += 5;\n    }\n    \n    // Ads indicators\n    if (className.match(/ad|ads|advert|banner/) || id.match(/ad|ads|advert|banner/)) {\n      scores.advertisement += 5;\n    }\n\n    return scores;\n  },\n\n  /**\n   * Analyzes element position on the page\n   */\n  position(element: HTMLElement): Record<SectionType, number> {\n    const scores: Record<SectionType, number> = { } as Record<SectionType, number>;\n    Object.keys(DEFAULT_OPTIONS.highlightColors || {}).forEach(key => {\n      scores[key as SectionType] = 0;\n    });\n\n    const rect = element.getBoundingClientRect();\n    const windowHeight = window.innerHeight;\n    const windowWidth = window.innerWidth;\n    \n    // Top position suggests header or navigation\n    if (rect.top < windowHeight * 0.2) {\n      scores.header += 3;\n      scores.navigation += 2;\n    }\n    \n    // Bottom position suggests footer\n    if (rect.bottom > windowHeight * 0.8) {\n      scores.footer += 3;\n    }\n    \n    // Left side suggests sidebar\n    if (rect.left < windowWidth * 0.2 && rect.width < windowWidth * 0.3) {\n      scores.sidebar += 3;\n      scores.navigation += 1;\n    }\n    \n    // Right side suggests sidebar\n    if (rect.right > windowWidth * 0.8 && rect.width < windowWidth * 0.3) {\n      scores.sidebar += 3;\n    }\n    \n    // Central position suggests main content\n    if (rect.left > windowWidth * 0.2 && rect.right < windowWidth * 0.8) {\n      scores['main-content'] += 3;\n      scores.article += 2;\n    }\n\n    // Full width at top often indicates navigation or header\n    if (rect.width > windowWidth * 0.9 && rect.top < windowHeight * 0.2) {\n      scores.navigation += 2;\n      scores.header += 2;\n    }\n\n    return scores;\n  },\n\n  /**\n   * Analyzes content characteristics\n   */\n  content(element: HTMLElement): Record<SectionType, number> {\n    const scores: Record<SectionType, number> = { } as Record<SectionType, number>;\n    Object.keys(DEFAULT_OPTIONS.highlightColors || {}).forEach(key => {\n      scores[key as SectionType] = 0;\n    });\n\n    // Count different types of elements\n    const links = element.querySelectorAll('a');\n    const paragraphs = element.querySelectorAll('p');\n    const headings = element.querySelectorAll('h1, h2, h3, h4, h5, h6');\n    const images = element.querySelectorAll('img');\n    const forms = element.querySelectorAll('form');\n    const inputs = element.querySelectorAll('input');\n    // const buttons = element.querySelectorAll('button');\n    // const lists = element.querySelectorAll('ul, ol');\n    \n    // Navigation usually has many links, often in lists\n    if (links.length > 5 && links.length / element.textContent!.length > 0.1) {\n      scores.navigation += 3;\n    }\n    \n    // Main content usually has paragraphs and headings\n    if (paragraphs.length > 2 && headings.length >= 1) {\n      scores['main-content'] += 3;\n      scores.article += 2;\n    }\n    \n    // Articles often have paragraphs, headings, and images\n    if (paragraphs.length > 3 && headings.length >= 1 && images.length >= 1) {\n      scores.article += 3;\n    }\n    \n    // Search usually has a form with inputs\n    if (forms.length >= 1 && inputs.length >= 1) {\n      // Specifically look for search input types or placeholder text\n      const searchInputs = Array.from(inputs).filter(input => \n        input.getAttribute('type') === 'search' || \n        input.getAttribute('placeholder')?.toLowerCase().includes('search')\n      );\n      \n      if (searchInputs.length > 0) {\n        scores.search += 4;\n      } else {\n        scores.form += 3;\n      }\n    }\n    \n    // Comments sections often have repeated similar structures\n    const commentPatterns = element.querySelectorAll('.comment, .response, [id^=\"comment-\"]');\n    if (commentPatterns.length > 1) {\n      scores.comments += 4;\n    }\n    \n    // Social links often have recognizable icons or text\n    const socialPatterns = Array.from(links).filter(link => {\n      const href = link.getAttribute('href') || '';\n      const text = link.textContent?.toLowerCase() || '';\n      return href.match(/facebook|twitter|instagram|linkedin|youtube/) || \n             text.match(/facebook|twitter|instagram|linkedin|youtube|share|follow/);\n    });\n    \n    if (socialPatterns.length > 1) {\n      scores['social-links'] += 4;\n    }\n    \n    // Sidebar often has widgets and less text\n    if (element.querySelectorAll('.widget, aside, [class*=\"widget\"]').length > 0) {\n      scores.sidebar += 3;\n    }\n\n    return scores;\n  },\n\n  /**\n   * Analyzes ARIA roles and landmarks\n   */\n  aria(element: HTMLElement): Record<SectionType, number> {\n    const scores: Record<SectionType, number> = { } as Record<SectionType, number>;\n    Object.keys(DEFAULT_OPTIONS.highlightColors || {}).forEach(key => {\n      scores[key as SectionType] = 0;\n    });\n\n    const role = element.getAttribute('role');\n    \n    if (role) {\n      switch (role) {\n        case 'navigation':\n          scores.navigation = 10;\n          break;\n        case 'banner':\n          scores.header = 10;\n          break;\n        case 'contentinfo':\n          scores.footer = 10;\n          break;\n        case 'complementary':\n          scores.sidebar = 10;\n          break;\n        case 'main':\n          scores['main-content'] = 10;\n          break;\n        case 'article':\n          scores.article = 10;\n          break;\n        case 'search':\n          scores.search = 10;\n          break;\n        case 'form':\n          scores.form = 8;\n          break;\n      }\n    }\n\n    return scores;\n  }\n};\n\n/**\n * Usage example\n */\nexport function analyzeAndHighlightPage(): void {\n  const analyzer = new DOMStructureAnalyzer();\n  analyzer.analyze();\n  analyzer.highlight();\n  \n  console.log('DOM analysis complete');\n  console.log('Detected sections:', analyzer.getSectionMap());\n} ","/**\n * Browser action helper functions for AI agent interactions\n * These standalone functions can be used in agent workflows to interact with web pages\n */\n\n/**\n * Click on an element matching the provided selector\n * @param selector CSS selector for the target element\n * @returns Promise resolving to true if click was successful, false otherwise\n */\nexport async function clickElement(selector: string): Promise<boolean> {\n  try {\n    const element = document.querySelector(selector);\n    if (element && element instanceof HTMLElement) {\n      element.click();\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error(`Error clicking element ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Fill a form input with the provided value\n * @param selector CSS selector for the input element\n * @param value Value to enter into the input\n * @returns Promise resolving to true if input was filled successfully, false otherwise\n */\nexport async function fillInput(selector: string, value: string): Promise<boolean> {\n  try {\n    const element = document.querySelector(selector);\n    if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n      element.value = value;\n      \n      // Trigger input and change events to simulate user typing\n      element.dispatchEvent(new Event('input', { bubbles: true }));\n      element.dispatchEvent(new Event('change', { bubbles: true }));\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error(`Error filling input ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Select an option from a dropdown\n * @param selector CSS selector for the select element\n * @param value Value to select\n * @returns Promise resolving to true if selection was successful, false otherwise\n */\nexport async function selectOption(selector: string, value: string): Promise<boolean> {\n  try {\n    const element = document.querySelector(selector);\n    if (element instanceof HTMLSelectElement) {\n      element.value = value;\n      element.dispatchEvent(new Event('change', { bubbles: true }));\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error(`Error selecting option in ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Scroll the page in the specified direction and amount\n * @param options Scroll options including direction and amount\n * @returns Promise resolving to void\n */\nexport async function scrollPage(options: { direction: 'up' | 'down', amount: number }): Promise<void> {\n  try {\n    window.scrollBy({\n      top: options.direction === 'down' ? options.amount : -options.amount,\n      behavior: 'smooth'\n    });\n    \n    // Wait for scroll to complete\n    return new Promise(resolve => setTimeout(resolve, 300));\n  } catch (error) {\n    console.error('Error scrolling page:', error);\n  }\n}\n\n/**\n * Navigate to a specified URL\n * @param url URL to navigate to\n * @returns Promise resolving to void\n */\nexport async function navigateTo(url: string): Promise<void> {\n  try {\n    window.location.href = url;\n  } catch (error) {\n    console.error(`Error navigating to ${url}:`, error);\n  }\n}\n\n/**\n * Wait for an element to appear in the DOM\n * @param selector CSS selector for the element to wait for\n * @param timeout Maximum time to wait in milliseconds\n * @returns Promise resolving to the element if found, null if timeout\n */\nexport async function waitForElement(selector: string, timeout = 5000): Promise<Element | null> {\n  return new Promise(resolve => {\n    const element = document.querySelector(selector);\n    if (element) {\n      resolve(element);\n      return;\n    }\n\n    const startTime = Date.now();\n    const checkInterval = setInterval(() => {\n      const element = document.querySelector(selector);\n      if (element) {\n        clearInterval(checkInterval);\n        resolve(element);\n      } else if (Date.now() - startTime > timeout) {\n        clearInterval(checkInterval);\n        resolve(null);\n      }\n    }, 100);\n  });\n}\n\n/**\n * Extract text content from an element\n * @param selector CSS selector for the target element\n * @returns Promise resolving to the text content or empty string if element not found\n */\nexport async function extractText(selector: string): Promise<string> {\n  try {\n    const element = document.querySelector(selector);\n    return element ? element.textContent?.trim() || '' : '';\n  } catch (error) {\n    console.error(`Error extracting text from ${selector}:`, error);\n    return '';\n  }\n}\n\n/**\n * Check if an element exists in the DOM\n * @param selector CSS selector for the element to check\n * @returns Promise resolving to true if element exists, false otherwise\n */\nexport async function elementExists(selector: string): Promise<boolean> {\n  try {\n    return document.querySelector(selector) !== null;\n  } catch (error) {\n    console.error(`Error checking if element exists ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Find all elements matching a selector and return their text content\n * @param selector CSS selector for the elements to find\n * @returns Promise resolving to array of text content from matching elements\n */\nexport async function findAllElements(selector: string): Promise<string[]> {\n  try {\n    const elements = document.querySelectorAll(selector);\n    return Array.from(elements).map(el => el.textContent?.trim() || '');\n  } catch (error) {\n    console.error(`Error finding elements ${selector}:`, error);\n    return [];\n  }\n}\n\n/**\n * Submit a form\n * @param selector CSS selector for the form element\n * @returns Promise resolving to true if submission was successful, false otherwise\n */\nexport async function submitForm(selector: string): Promise<boolean> {\n  try {\n    const form = document.querySelector(selector);\n    if (form instanceof HTMLFormElement) {\n      form.submit();\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error(`Error submitting form ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Focus on an element\n * @param selector CSS selector for the element to focus\n * @returns Promise resolving to true if focus was successful, false otherwise\n */\nexport async function focusElement(selector: string): Promise<boolean> {\n  try {\n    const element = document.querySelector(selector);\n    if (element instanceof HTMLElement) {\n      element.focus();\n      return true;\n    }\n    return false;\n  } catch (error) {\n    console.error(`Error focusing element ${selector}:`, error);\n    return false;\n  }\n}\n\n/**\n * Get attributes of an element\n * @param selector CSS selector for the target element\n * @param attributeNames Array of attribute names to retrieve\n * @returns Promise resolving to object with attribute name-value pairs\n */\nexport async function getElementAttributes(\n  selector: string, \n  attributeNames: string[]\n): Promise<Record<string, string>> {\n  try {\n    const element = document.querySelector(selector);\n    if (!element) return {};\n    \n    const attributes: Record<string, string> = {};\n    attributeNames.forEach(attr => {\n      const value = element.getAttribute(attr);\n      if (value !== null) {\n        attributes[attr] = value;\n      }\n    });\n    \n    return attributes;\n  } catch (error) {\n    console.error(`Error getting attributes from ${selector}:`, error);\n    return {};\n  }\n} ","/**\n * PDF Parser for extracting text from PDF files\n * Uses PDF.js library for parsing PDF documents in the browser\n */\n\n/* eslint-disable no-console */\n\n// We'll use the PDF.js library which needs to be included in the project\n// This interface represents the PDF.js library types we'll use\ninterface PDFJSStatic {\n  getDocument: (source: Uint8Array | { url: string }) => PDFDocumentLoadingTask;\n  GlobalWorkerOptions?: {\n    workerSrc: string;\n  };\n  version?: string;\n}\n\ninterface PDFDocumentLoadingTask {\n  promise: Promise<PDFDocumentProxy>;\n}\n\ninterface PDFDocumentProxy {\n  numPages: number;\n  getPage: (pageNumber: number) => Promise<PDFPageProxy>;\n}\n\ninterface PDFPageProxy {\n  getTextContent: () => Promise<PDFTextContent>;\n}\n\ninterface PDFTextContent {\n  items: Array<{ str: string }>;\n}\n\n// Helper function to get the PDF.js library\nfunction getPdfLib(): PDFJSStatic {\n  if (typeof window === 'undefined') {\n    throw new Error('PDF.js can only be used in browser environments');\n  }\n  \n  const pdfjsLib = (window as any).pdfjsLib;\n  \n  if (!pdfjsLib) {\n    throw new Error('PDF.js library not found. Make sure to include it in your project.');\n  }\n  \n  console.log('PDF.js library found:', pdfjsLib);\n  \n  // Ensure worker is set - check if workerSrc can be set directly\n  if (pdfjsLib.GlobalWorkerOptions) {\n    try {\n      // Only try to set the workerSrc property if it's not already set\n      if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {\n        pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js';\n      }\n    } catch (e) {\n      console.warn('Could not set PDF.js worker source:', e);\n      // You might need an alternative approach here depending on the PDF.js version\n    }\n  }\n  \n  return pdfjsLib;\n}\n\n// Declare PDF.js as a global variable that will be loaded externally\ndeclare const pdfjsLib: PDFJSStatic;\n\n/**\n * Options for PDF parsing\n */\nexport interface PDFParseOptions {\n  /**\n   * Maximum number of pages to parse (default: all pages)\n   */\n  maxPages?: number;\n  \n  /**\n   * Whether to include page numbers in the output (default: false)\n   */\n  includePageNumbers?: boolean;\n  \n  /**\n   * Custom page separator (default: \"\\n\\n\")\n   */\n  pageSeparator?: string;\n  \n  /**\n   * Debug mode (default: false)\n   */\n  debug?: boolean;\n}\n\n/**\n * Result of PDF parsing\n */\nexport interface PDFParseResult {\n  /**\n   * The extracted text content\n   */\n  text: string;\n  \n  /**\n   * Number of pages in the document\n   */\n  numPages: number;\n  \n  /**\n   * Text content by page\n   */\n  pages: string[];\n  \n  /**\n   * Any errors encountered during parsing\n   */\n  errors?: string[];\n  \n  /**\n   * Debug information about the parsing process\n   */\n  debugInfo?: string[];\n}\n\n/**\n * PDF Parser class for extracting text from PDF files\n */\nexport class PDFParser {\n  /**\n   * Parse a PDF file from a URL\n   * \n   * @param url URL of the PDF file to parse\n   * @param options Parsing options\n   * @returns Promise resolving to the parsed PDF content\n   */\n  static async parseFromUrl(url: string, options: PDFParseOptions = {}): Promise<PDFParseResult> {\n    const debugInfo: string[] = [];\n    if (options.debug) debugInfo.push(`Starting URL parsing: ${url}`);\n    console.log(`Starting URL parsing: ${url}`);\n    \n    try {\n      // Get PDF.js library\n      const pdfjsLib = getPdfLib();\n      if (options.debug) debugInfo.push('PDF.js library found');\n      \n      // Load the PDF document\n      if (options.debug) debugInfo.push('Loading PDF document from URL...');\n      console.log('Loading PDF document from URL...');\n      \n      const loadingTask = pdfjsLib.getDocument({ url });\n      const pdf = await loadingTask.promise;\n      \n      if (options.debug) debugInfo.push(`PDF loaded successfully. Pages: ${pdf.numPages}`);\n      console.log(`PDF loaded successfully. Pages: ${pdf.numPages}`);\n      \n      return this.extractTextFromPdf(pdf, options, debugInfo);\n    } catch (error) {\n      const errorMessage = (error as Error).message;\n      if (options.debug) debugInfo.push(`Error: ${errorMessage}`);\n      console.error('PDF parsing error:', error);\n      \n      return {\n        text: '',\n        numPages: 0,\n        pages: [],\n        errors: [errorMessage],\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n  \n  /**\n   * Parse a PDF file from an ArrayBuffer\n   * \n   * @param data ArrayBuffer containing the PDF data\n   * @param options Parsing options\n   * @returns Promise resolving to the parsed PDF content\n   */\n  static async parseFromData(data: ArrayBuffer, options: PDFParseOptions = {}): Promise<PDFParseResult> {\n    const debugInfo: string[] = [];\n    if (options.debug) debugInfo.push(`Starting ArrayBuffer parsing. Size: ${data.byteLength} bytes`);\n    console.log(`Starting ArrayBuffer parsing. Size: ${data.byteLength} bytes`);\n    \n    try {\n      // Get PDF.js library\n      const pdfjsLib = getPdfLib();\n      if (options.debug) debugInfo.push('PDF.js library found');\n      \n      // Convert ArrayBuffer to Uint8Array\n      const uint8Array = new Uint8Array(data);\n      if (options.debug) debugInfo.push(`Converted to Uint8Array. Length: ${uint8Array.length}`);\n      console.log(`Converted to Uint8Array. Length: ${uint8Array.length}`);\n      \n      // Load the PDF document\n      if (options.debug) debugInfo.push('Loading PDF document from data...');\n      console.log('Loading PDF document from data...');\n      \n      try {\n        const loadingTask = pdfjsLib.getDocument(uint8Array);\n        console.log('Loading task created:', loadingTask);\n        \n        const pdf = await loadingTask.promise;\n        console.log('PDF loaded successfully:', pdf);\n        console.log('Number of pages:', pdf.numPages);\n        \n        if (options.debug) debugInfo.push(`PDF loaded successfully. Pages: ${pdf.numPages}`);\n        \n        return this.extractTextFromPdf(pdf, options, debugInfo);\n      } catch (loadError) {\n        console.error('Error loading PDF:', loadError);\n        throw loadError;\n      }\n    } catch (error) {\n      const errorMessage = (error as Error).message;\n      if (options.debug) debugInfo.push(`Error: ${errorMessage}`);\n      console.error('PDF parsing error:', error);\n      \n      return {\n        text: '',\n        numPages: 0,\n        pages: [],\n        errors: [errorMessage],\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n  \n  /**\n   * Extract text content from a PDF document\n   * \n   * @param pdf PDF document proxy\n   * @param options Parsing options\n   * @returns Promise resolving to the parsed PDF content\n   */\n  private static async extractTextFromPdf(\n    pdf: PDFDocumentProxy, \n    options: PDFParseOptions,\n    debugInfo: string[]\n  ): Promise<PDFParseResult> {\n    const { \n      maxPages = pdf.numPages,\n      includePageNumbers = false,\n      pageSeparator = '\\n\\n'\n    } = options;\n    \n    const pageTexts: string[] = [];\n    const errors: string[] = [];\n    \n    // Determine how many pages to process\n    const pagesToProcess = Math.min(maxPages, pdf.numPages);\n    \n    // Process each page\n    for (let i = 1; i <= pagesToProcess; i++) {\n      try {\n        const page = await pdf.getPage(i);\n        const textContent = await page.getTextContent();\n        \n        let pageText = textContent.items.map(item => item.str).join(' ');\n        \n        // Add page number if requested\n        if (includePageNumbers) {\n          pageText = `[Page ${i}]\\n${pageText}`;\n        }\n        \n        pageTexts.push(pageText);\n      } catch (error) {\n        errors.push(`Error extracting text from page ${i}: ${(error as Error).message}`);\n      }\n    }\n    \n    // Combine all page texts\n    const fullText = pageTexts.join(pageSeparator);\n    \n    return {\n      text: fullText,\n      numPages: pdf.numPages,\n      pages: pageTexts,\n      errors: errors.length > 0 ? errors : undefined,\n      debugInfo: options.debug ? debugInfo : undefined\n    };\n  }\n  \n  /**\n   * Loads the PDF.js library from a CDN if not already available\n   * @param pdfJsPath Path to the PDF.js library\n   * @param workerPath Path to the PDF.js worker\n   */\n  static async loadPdfJsLibrary(\n    pdfJsPath: string = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js',\n    workerPath: string = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js'\n  ): Promise<void> {\n    // Check if PDF.js is already available\n    if ((window as any).pdfjsLib) {\n      return;\n    }\n\n    // Check if we're in a browser extension environment\n    const isExtension = typeof window !== 'undefined' && \n                       typeof (window as any).chrome !== 'undefined' && \n                       (window as any).chrome.runtime && \n                       (window as any).chrome.runtime.id;\n    \n    if (isExtension) {\n      try {\n        // For extensions, use dynamic import with a fallback\n        let pdfjs;\n        try {\n          // Try to use bundled version first\n          pdfjs = await import('pdfjs-dist');\n        } catch (e) {\n          // Fallback to window global if import fails\n          if (!(window as any).pdfjsLib) {\n            throw new Error('PDF.js not available');\n          }\n          pdfjs = (window as any).pdfjsLib;\n        }\n        \n        // Set up worker\n        if (pdfjs.GlobalWorkerOptions && !pdfjs.GlobalWorkerOptions.workerSrc) {\n          const chrome = (window as any).chrome;\n          if (chrome && chrome.runtime && chrome.runtime.getURL) {\n            pdfjs.GlobalWorkerOptions.workerSrc = chrome.runtime.getURL('pdf.worker.min.js');\n          } else {\n            pdfjs.GlobalWorkerOptions.workerSrc = workerPath;\n          }\n        }\n        \n        // Assign to window\n        (window as any).pdfjsLib = pdfjs;\n      } catch (error) {\n        console.error('Error loading PDF.js:', error);\n        throw error;\n      }\n    } else {\n      // For non-extension environments, load from CDN\n      return new Promise((resolve, reject) => {\n        const script = document.createElement('script');\n        script.src = pdfJsPath;\n        script.onload = () => {\n          (window as any).pdfjsLib.GlobalWorkerOptions.workerSrc = workerPath;\n          resolve();\n        };\n        script.onerror = () => reject(new Error('Failed to load PDF.js'));\n        document.head.appendChild(script);\n      });\n    }\n  }\n\n  /**\n   * Checks if PDF.js is available in the current environment\n   */\n  static isPdfJsAvailable(): boolean {\n    return typeof window !== 'undefined' && !!(window as any).pdfjsLib;\n  }\n}\n\n/**\n * Utility function to extract text from a PDF file\n * \n * @param source URL or ArrayBuffer of the PDF file\n * @param options Parsing options\n * @returns Promise resolving to the parsed PDF content\n */\nexport async function extractTextFromPdf(\n  source: string | ArrayBuffer,\n  options: PDFParseOptions = {}\n): Promise<string> {\n  let result: PDFParseResult;\n  \n  if (typeof source === 'string') {\n    result = await PDFParser.parseFromUrl(source, options);\n  } else {\n    result = await PDFParser.parseFromData(source, options);\n  }\n  \n  return result.text;\n}\n\n/**\n * Utility function to extract structured text from a PDF file with page information\n * \n * @param source URL or ArrayBuffer of the PDF file\n * @param options Parsing options\n * @returns Promise resolving to the parsed PDF content with page information\n */\nexport async function extractStructuredTextFromPdf(\n  source: string | ArrayBuffer,\n  options: PDFParseOptions = {}\n): Promise<PDFParseResult> {\n  if (typeof source === 'string') {\n    return await PDFParser.parseFromUrl(source, options);\n  } else {\n    return await PDFParser.parseFromData(source, options);\n  }\n}\n\n// Instead, initialize PDF.js when needed in a function\nfunction initializePdfJs() {\n  // Only run this in browser environments\n  if (typeof window !== 'undefined') {\n    // Check if PDF.js is already loaded\n    if (!(window as any).pdfjsLib) {\n      console.log('PDF.js not loaded, will load on demand when needed');\n    }\n  }\n}\n\n// Call this function instead of using top-level await\ninitializePdfJs();\n\n/**\n * Formats PDF text with page numbers and additional metadata\n * @param result The parsed PDF result\n * @param options Formatting options\n * @returns Formatted text representation of the PDF\n */\nexport function pdfToText(\n  result: PDFParseResult,\n  options: {\n    includePageNumbers?: boolean;\n    includeSummary?: boolean;\n    pagePrefix?: string;\n    pageSuffix?: string;\n  } = {}\n): string {\n  // Default options\n  const includePageNumbers = options.includePageNumbers !== false;\n  const includeSummary = options.includeSummary !== false;\n  const pagePrefix = options.pagePrefix || '--- Page ';\n  const pageSuffix = options.pageSuffix || ' ---';\n  \n  const lines: string[] = [];\n  \n  // Add each page with optional page numbers\n  if (includePageNumbers) {\n    for (let i = 0; i < result.pages.length; i++) {\n      const pageNum = i + 1;\n      lines.push(`${pagePrefix}${pageNum}${pageSuffix}`);\n      lines.push(result.pages[i]);\n      lines.push(''); // Empty line between pages\n    }\n  } else {\n    // Just concatenate all pages\n    lines.push(result.text);\n  }\n  \n  // Add summary information\n  if (includeSummary) {\n    lines.push('');\n    lines.push(`PDF Summary: ${result.numPages} pages`);\n    \n    if (result.errors && result.errors.length > 0) {\n      lines.push('Errors encountered during parsing:');\n      result.errors.forEach(error => {\n        lines.push(`- ${error}`);\n      });\n    }\n  }\n  \n  return lines.join('\\n');\n}\n\n/**\n * Processes a PDF file and returns both text and structured data\n * This is a convenience function that handles buffer copying and multiple extractions\n * \n * @param file The PDF file to process\n * @param options Parsing options\n * @returns An object containing text, structured data, and debug information\n */\nexport async function processPdfFile(\n  file: File,\n  options: PDFParseOptions & {\n    textFormatting?: {\n      includePageNumbers?: boolean;\n      includeSummary?: boolean;\n      pagePrefix?: string;\n      pageSuffix?: string;\n    }\n  } = {}\n): Promise<{\n  text: string;\n  structured: PDFParseResult;\n  formattedText: string; // New property for AI-friendly text\n  debugInfo: string[];\n}> {\n  const debugInfo: string[] = [];\n  \n  // Validate file\n  if (!file || file.type !== 'application/pdf') {\n    throw new Error('Invalid file: Must be a PDF');\n  }\n  \n  debugInfo.push(`Processing PDF: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);\n  \n  try {\n    // Read the file as ArrayBuffer\n    const fileBuffer = await file.arrayBuffer();\n    debugInfo.push('File loaded as ArrayBuffer');\n    \n    // Create copies to prevent detachment issues\n    const textBuffer = fileBuffer.slice(0);\n    const structuredBuffer = fileBuffer.slice(0);\n    \n    // Ensure PDF.js is available\n    if (!PDFParser.isPdfJsAvailable()) {\n      debugInfo.push('PDF.js not available, loading from CDN...');\n      await PDFParser.loadPdfJsLibrary();\n      debugInfo.push('PDF.js loaded successfully');\n    }\n    \n    // Extract text\n    debugInfo.push('Extracting text from PDF...');\n    const text = await extractTextFromPdf(textBuffer, options);\n    debugInfo.push(`Text extracted successfully (${text.length} characters)`);\n    \n    // Extract structured data\n    debugInfo.push('Extracting structured data...');\n    const structured = await extractStructuredTextFromPdf(structuredBuffer, options);\n    debugInfo.push(`Structured data extracted (${structured.numPages} pages)`);\n    \n    // Create AI-friendly formatted text\n    debugInfo.push('Creating formatted text for AI...');\n    const formattedText = pdfToText(structured, options.textFormatting);\n    debugInfo.push(`Formatted text created (${formattedText.length} characters)`);\n    \n    return {\n      text,\n      structured,\n      formattedText,\n      debugInfo\n    };\n  } catch (error) {\n    debugInfo.push(`Error: ${error instanceof Error ? error.message : String(error)}`);\n    throw error;\n  }\n}\n","/**\n * CSV Parser for BrowserAI\n * Provides functionality to parse CSV files in browser environments\n */\n\n/**\n * Options for CSV parsing\n */\nexport interface CSVParseOptions {\n  /**\n   * Whether to include headers in the output (default: true)\n   */\n  includeHeaders?: boolean;\n  \n  /**\n   * Custom delimiter (default: \",\")\n   */\n  delimiter?: string;\n  \n  /**\n   * Whether to trim whitespace from values (default: true)\n   */\n  trimValues?: boolean;\n  \n  /**\n   * Whether to skip empty lines (default: true)\n   */\n  skipEmptyLines?: boolean;\n  \n  /**\n   * Custom quote character (default: '\"')\n   */\n  quoteChar?: string;\n  \n  /**\n   * Debug mode (default: false)\n   */\n  debug?: boolean;\n}\n\n/**\n * Result of CSV parsing\n */\nexport interface CSVParseResult {\n  /**\n   * Headers from the CSV file\n   */\n  headers: string[];\n  \n  /**\n   * Data rows as arrays of values\n   */\n  rows: string[][];\n  \n  /**\n   * Data as an array of objects (using headers as keys)\n   */\n  data: Record<string, string>[];\n  \n  /**\n   * Total number of rows (excluding headers if present)\n   */\n  rowCount: number;\n  \n  /**\n   * Total number of columns\n   */\n  columnCount: number;\n  \n  /**\n   * Any errors encountered during parsing\n   */\n  errors?: string[];\n  \n  /**\n   * Debug information\n   */\n  debugInfo?: string[];\n}\n\n/**\n * CSV Parser class\n */\nexport class CSVParser {\n  /**\n   * Parse CSV content from a string\n   * @param content CSV content as string\n   * @param options Parsing options\n   * @returns Parsed CSV data\n   */\n  static parseFromString(content: string, options: CSVParseOptions = {}): CSVParseResult {\n    const debugInfo: string[] = options.debug ? ['Parsing CSV from string'] : [];\n    const errors: string[] = [];\n    \n    // Set default options\n    const delimiter = options.delimiter || ',';\n    const quoteChar = options.quoteChar || '\"';\n    const includeHeaders = options.includeHeaders !== false;\n    const trimValues = options.trimValues !== false;\n    const skipEmptyLines = options.skipEmptyLines !== false;\n    \n    if (options.debug) {\n      debugInfo.push(`Options: delimiter=\"${delimiter}\", quoteChar=\"${quoteChar}\", includeHeaders=${includeHeaders}, trimValues=${trimValues}, skipEmptyLines=${skipEmptyLines}`);\n    }\n    \n    try {\n      // Split content into lines\n      let lines = content.split(/\\r?\\n/);\n      \n      if (skipEmptyLines) {\n        lines = lines.filter(line => line.trim() !== '');\n      }\n      \n      if (options.debug) {\n        debugInfo.push(`Found ${lines.length} lines in CSV`);\n      }\n      \n      if (lines.length === 0) {\n        errors.push('CSV content is empty');\n        return {\n          headers: [],\n          rows: [],\n          data: [],\n          rowCount: 0,\n          columnCount: 0,\n          errors,\n          debugInfo\n        };\n      }\n      \n      // Parse lines into rows\n      const rows: string[][] = [];\n      for (let i = 0; i < lines.length; i++) {\n        const line = lines[i];\n        const row = this.parseLine(line, delimiter, quoteChar, trimValues);\n        rows.push(row);\n      }\n      \n      // Extract headers and data\n      let headers: string[] = [];\n      let data: Record<string, string>[] = [];\n      \n      if (includeHeaders && rows.length > 0) {\n        headers = rows[0];\n        const dataRows = rows.slice(1);\n        \n        // Convert to array of objects\n        data = dataRows.map(row => {\n          const obj: Record<string, string> = {};\n          headers.forEach((header, index) => {\n            obj[header] = index < row.length ? row[index] : '';\n          });\n          return obj;\n        });\n      } else {\n        // No headers, use indices as keys\n        data = rows.map(row => {\n          const obj: Record<string, string> = {};\n          row.forEach((value, index) => {\n            obj[`column${index + 1}`] = value;\n          });\n          return obj;\n        });\n      }\n      \n      const columnCount = rows.length > 0 ? rows[0].length : 0;\n      const rowCount = includeHeaders && rows.length > 0 ? rows.length - 1 : rows.length;\n      \n      if (options.debug) {\n        debugInfo.push(`Parsed ${rowCount} data rows with ${columnCount} columns`);\n      }\n      \n      return {\n        headers,\n        rows: includeHeaders && rows.length > 0 ? rows.slice(1) : rows,\n        data,\n        rowCount,\n        columnCount,\n        errors: errors.length > 0 ? errors : undefined,\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      errors.push(`Error parsing CSV: ${errorMessage}`);\n      \n      if (options.debug) {\n        debugInfo.push(`Error: ${errorMessage}`);\n      }\n      \n      return {\n        headers: [],\n        rows: [],\n        data: [],\n        rowCount: 0,\n        columnCount: 0,\n        errors,\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n  \n  /**\n   * Parse a single CSV line into an array of values\n   */\n  private static parseLine(line: string, delimiter: string, quoteChar: string, trimValues: boolean): string[] {\n    const values: string[] = [];\n    let currentValue = '';\n    let inQuotes = false;\n    \n    for (let i = 0; i < line.length; i++) {\n      const char = line[i];\n      const nextChar = i < line.length - 1 ? line[i + 1] : '';\n      \n      if (char === quoteChar) {\n        if (inQuotes && nextChar === quoteChar) {\n          // Escaped quote\n          currentValue += quoteChar;\n          i++; // Skip the next quote\n        } else {\n          // Toggle quote mode\n          inQuotes = !inQuotes;\n        }\n      } else if (char === delimiter && !inQuotes) {\n        // End of value\n        values.push(trimValues ? currentValue.trim() : currentValue);\n        currentValue = '';\n      } else {\n        // Add character to current value\n        currentValue += char;\n      }\n    }\n    \n    // Add the last value\n    values.push(trimValues ? currentValue.trim() : currentValue);\n    \n    return values;\n  }\n  \n  /**\n   * Parse CSV from a File object\n   * @param file CSV file\n   * @param options Parsing options\n   * @returns Promise resolving to parsed CSV data\n   */\n  static async parseFromFile(file: File, options: CSVParseOptions = {}): Promise<CSVParseResult> {\n    const debugInfo: string[] = options.debug ? [`Parsing CSV file: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`] : [];\n    \n    try {\n      const text = await file.text();\n      \n      if (options.debug) {\n        debugInfo.push(`File loaded as text, length: ${text.length} characters`);\n      }\n      \n      const result = this.parseFromString(text, options);\n      \n      if (options.debug && debugInfo.length > 0) {\n        result.debugInfo = [...debugInfo, ...(result.debugInfo || [])];\n      }\n      \n      return result;\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      \n      if (options.debug) {\n        debugInfo.push(`Error reading file: ${errorMessage}`);\n      }\n      \n      return {\n        headers: [],\n        rows: [],\n        data: [],\n        rowCount: 0,\n        columnCount: 0,\n        errors: [`Error reading CSV file: ${errorMessage}`],\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n}\n\n/**\n * Converts parsed CSV data to a formatted text string\n * @param csvData The parsed CSV data\n * @param options Formatting options\n * @returns Formatted text representation of the CSV data\n */\nexport function csvToText(\n  csvData: CSVParseResult,\n  options: {\n    includeHeaders?: boolean;\n    columnSeparator?: string;\n    rowSeparator?: string;\n    maxRows?: number;\n    maxColumnWidth?: number;\n  } = {}\n): string {\n  // Default options\n  const includeHeaders = options.includeHeaders !== false;\n  const columnSeparator = options.columnSeparator || ' | ';\n  const rowSeparator = options.rowSeparator || '\\n';\n  const maxRows = options.maxRows || Infinity;\n  const maxColumnWidth = options.maxColumnWidth || 50;\n  \n  // Function to truncate long values\n  const truncate = (value: string): string => {\n    if (value.length <= maxColumnWidth) return value;\n    return value.substring(0, maxColumnWidth - 3) + '...';\n  };\n  \n  const lines: string[] = [];\n  \n  // Add headers if requested\n  if (includeHeaders && csvData.headers.length > 0) {\n    lines.push(csvData.headers.map(h => truncate(h)).join(columnSeparator));\n    \n    // Add separator line\n    if (csvData.headers.length > 0) {\n      const separatorLine = csvData.headers.map(() => '-'.repeat(10)).join(columnSeparator);\n      lines.push(separatorLine);\n    }\n  }\n  \n  // Add data rows\n  const rowsToInclude = Math.min(csvData.rows.length, maxRows);\n  for (let i = 0; i < rowsToInclude; i++) {\n    const row = csvData.rows[i];\n    lines.push(row.map(cell => truncate(cell)).join(columnSeparator));\n  }\n  \n  // Add indication if rows were truncated\n  if (csvData.rows.length > maxRows) {\n    lines.push(`... (${csvData.rows.length - maxRows} more rows)`);\n  }\n  \n  // Add summary\n  lines.push('');\n  lines.push(`CSV Summary: ${csvData.rowCount} rows, ${csvData.columnCount} columns`);\n  \n  return lines.join(rowSeparator);\n}\n\n/**\n * Extract text representation from a CSV file\n * @param source CSV content as string or File\n * @param options Parsing and formatting options\n * @returns Promise resolving to text representation of the CSV\n */\nexport async function extractTextFromCSV(\n  source: string | File,\n  options: CSVParseOptions & {\n    textFormatting?: {\n      includeHeaders?: boolean;\n      columnSeparator?: string;\n      rowSeparator?: string;\n      maxRows?: number;\n      maxColumnWidth?: number;\n    }\n  } = {}\n): Promise<string> {\n  try {\n    let result: CSVParseResult;\n    \n    if (typeof source === 'string') {\n      result = CSVParser.parseFromString(source, options);\n    } else {\n      result = await CSVParser.parseFromFile(source, options);\n    }\n    \n    // Convert to text\n    return csvToText(result, options.textFormatting);\n  } catch (error) {\n    console.error('Error extracting text from CSV:', error);\n    return `Error extracting text from CSV: ${error instanceof Error ? error.message : String(error)}`;\n  }\n}\n\n/**\n * Processes a CSV file and returns both structured data and text representation\n * @param file The CSV file to process\n * @param options Parsing and formatting options\n * @returns Promise resolving to processed CSV data\n */\nexport async function processCSVFile(\n  file: File,\n  options: CSVParseOptions & {\n    textFormatting?: {\n      includeHeaders?: boolean;\n      columnSeparator?: string;\n      rowSeparator?: string;\n      maxRows?: number;\n      maxColumnWidth?: number;\n    }\n  } = {}\n): Promise<{\n  parsed: CSVParseResult;\n  text: string;\n  debugInfo: string[];\n}> {\n  const debugInfo: string[] = [];\n  \n  // Validate file\n  if (!file || (!file.name.toLowerCase().endsWith('.csv') && file.type !== 'text/csv')) {\n    throw new Error('Invalid file: Must be a CSV file');\n  }\n  \n  debugInfo.push(`Processing CSV: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);\n  \n  try {\n    // Parse the CSV file\n    debugInfo.push('Parsing CSV file...');\n    const parsed = await CSVParser.parseFromFile(file, {\n      ...options,\n      debug: true // Force debug for internal use\n    });\n    \n    debugInfo.push(`CSV parsed successfully: ${parsed.rowCount} rows, ${parsed.columnCount} columns`);\n    \n    if (parsed.debugInfo) {\n      debugInfo.push(...parsed.debugInfo);\n    }\n    \n    // Convert to text\n    debugInfo.push('Converting CSV to text format...');\n    const text = csvToText(parsed, options.textFormatting);\n    debugInfo.push(`Text conversion complete: ${text.length} characters`);\n    \n    return {\n      parsed,\n      text,\n      debugInfo\n    };\n  } catch (error) {\n    debugInfo.push(`Error: ${error instanceof Error ? error.message : String(error)}`);\n    throw error;\n  }\n}\n\n/**\n * Extract data from a CSV file as an array of objects\n * @param source CSV content as string or File\n * @param options Parsing options\n * @returns Promise resolving to array of objects\n */\nexport async function extractDataFromCSV(\n  source: string | File,\n  options: CSVParseOptions = {}\n): Promise<Record<string, string>[]> {\n  try {\n    let result: CSVParseResult;\n    \n    if (typeof source === 'string') {\n      result = CSVParser.parseFromString(source, options);\n    } else {\n      result = await CSVParser.parseFromFile(source, options);\n    }\n    \n    return result.data;\n  } catch (error) {\n    console.error('Error extracting data from CSV:', error);\n    return [];\n  }\n} ","/**\n * DOCX Parser for BrowserAI\n * Provides functionality to parse DOCX files in browser environments\n */\n\nimport mammoth from 'mammoth';\n\n/**\n * Options for DOCX parsing\n */\nexport interface DOCXParseOptions {\n  /**\n   * Whether to extract images (default: false)\n   */\n  extractImages?: boolean;\n  \n  /**\n   * Whether to preserve styles (default: false)\n   */\n  preserveStyles?: boolean;\n  \n  /**\n   * Whether to include headers and footers (default: true)\n   */\n  includeHeadersFooters?: boolean;\n  \n  /**\n   * Whether to extract document properties (default: false)\n   */\n  extractProperties?: boolean;\n  \n  /**\n   * Debug mode (default: false)\n   */\n  debug?: boolean;\n}\n\n/**\n * Result of DOCX parsing\n */\nexport interface DOCXParseResult {\n  /**\n   * The extracted text content\n   */\n  text: string;\n  \n  /**\n   * HTML representation of the document\n   */\n  html: string;\n  \n  /**\n   * Document properties (if extracted)\n   */\n  properties?: Record<string, string>;\n  \n  /**\n   * Document structure information\n   */\n  structure?: {\n    paragraphs: number;\n    tables: number;\n    images: number;\n    sections: number;\n  };\n  \n  /**\n   * Any errors encountered during parsing\n   */\n  errors?: string[];\n  \n  /**\n   * Debug information\n   */\n  debugInfo?: string[];\n}\n\n/**\n * DOCX Parser class\n */\nexport class DOCXParser {\n  /**\n   * Parse DOCX from a File object\n   * @param file DOCX file\n   * @param options Parsing options\n   * @returns Promise resolving to parsed DOCX data\n   */\n  static async parseFromFile(file: File, options: DOCXParseOptions = {}): Promise<DOCXParseResult> {\n    const debugInfo: string[] = options.debug ? [`Parsing DOCX file: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`] : [];\n    const errors: string[] = [];\n    \n    try {\n      // Read the file as ArrayBuffer\n      const arrayBuffer = await file.arrayBuffer();\n      \n      if (options.debug) {\n        debugInfo.push(`File loaded as ArrayBuffer, size: ${arrayBuffer.byteLength} bytes`);\n      }\n      \n      // Configure mammoth options\n      const mammothOptions: any = {\n        includeDefaultStyleMap: options.preserveStyles !== false,\n        includeEmbeddedStyleMap: options.preserveStyles !== false,\n        convertImage: options.extractImages ? mammoth.images.imgElement : undefined,\n        includeHeader: options.includeHeadersFooters !== false,\n        includeFooter: options.includeHeadersFooters !== false\n      };\n      \n      if (options.debug) {\n        debugInfo.push(`Mammoth options: ${JSON.stringify(mammothOptions)}`);\n      }\n      \n      // Convert DOCX to HTML\n      const result = await mammoth.convertToHtml({ arrayBuffer }, mammothOptions);\n      \n      if (options.debug) {\n        debugInfo.push(`Conversion to HTML complete, HTML length: ${result.value.length} characters`);\n        if (result.messages.length > 0) {\n          debugInfo.push(`Conversion messages: ${JSON.stringify(result.messages)}`);\n        }\n      }\n      \n      // Add any warnings to errors\n      result.messages.forEach(message => {\n        if (message.type === 'warning') {\n          errors.push(message.message);\n        }\n      });\n      \n      // Extract text from HTML\n      const text = this.extractTextFromHtml(result.value);\n      \n      if (options.debug) {\n        debugInfo.push(`Text extracted from HTML, length: ${text.length} characters`);\n      }\n      \n      // Extract document structure information\n      const structure = this.extractStructure(result.value);\n      \n      if (options.debug) {\n        debugInfo.push(`Document structure extracted: ${JSON.stringify(structure)}`);\n      }\n      \n      // Extract document properties if requested\n      let properties: Record<string, string> | undefined;\n      if (options.extractProperties) {\n        try {\n          properties = await this.extractProperties(arrayBuffer);\n          if (options.debug) {\n            debugInfo.push(`Document properties extracted: ${JSON.stringify(properties)}`);\n          }\n        } catch (error) {\n          const errorMessage = error instanceof Error ? error.message : String(error);\n          errors.push(`Failed to extract document properties: ${errorMessage}`);\n          if (options.debug) {\n            debugInfo.push(`Error extracting properties: ${errorMessage}`);\n          }\n        }\n      }\n      \n      return {\n        text,\n        html: result.value,\n        properties,\n        structure,\n        errors: errors.length > 0 ? errors : undefined,\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      errors.push(`Error parsing DOCX: ${errorMessage}`);\n      \n      if (options.debug) {\n        debugInfo.push(`Error: ${errorMessage}`);\n      }\n      \n      return {\n        text: '',\n        html: '',\n        structure: { paragraphs: 0, tables: 0, images: 0, sections: 0 },\n        errors,\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n  \n  /**\n   * Extract text from HTML\n   * @param html HTML content\n   * @returns Plain text\n   */\n  private static extractTextFromHtml(html: string): string {\n    // Create a DOM parser\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(html, 'text/html');\n    \n    // Extract text\n    return doc.body.textContent || '';\n  }\n  \n  /**\n   * Extract document structure information\n   * @param html HTML content\n   * @returns Structure information\n   */\n  private static extractStructure(html: string): DOCXParseResult['structure'] {\n    // Create a DOM parser\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(html, 'text/html');\n    \n    return {\n      paragraphs: doc.querySelectorAll('p').length,\n      tables: doc.querySelectorAll('table').length,\n      images: doc.querySelectorAll('img').length,\n      sections: doc.querySelectorAll('section, div.section').length\n    };\n  }\n  \n  /**\n   * Extract document properties\n   * @param arrayBuffer Document as ArrayBuffer\n   * @returns Document properties\n   */\n  private static async extractProperties(arrayBuffer: ArrayBuffer): Promise<Record<string, string>> {\n    // This is a simplified version - mammoth doesn't directly expose properties\n    // For a full implementation, you might need to use another library or parse the DOCX XML\n    \n    // Use the arrayBuffer parameter to avoid the TS6133 error\n    const size = arrayBuffer.byteLength;\n    \n    return {\n      note: 'Document properties extraction is limited in this version',\n      fileSize: `${(size / 1024).toFixed(2)} KB`\n    };\n  }\n  \n  /**\n   * Check if the file is a valid DOCX file\n   * @param file File to check\n   * @returns True if the file is a valid DOCX file\n   */\n  static isValidDocxFile(file: File): boolean {\n    return (\n      file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||\n      file.name.toLowerCase().endsWith('.docx')\n    );\n  }\n  \n  /**\n   * Check if the file is a valid DOC file\n   * @param file File to check\n   * @returns True if the file is a valid DOC file\n   */\n  static isValidDocFile(file: File): boolean {\n    return (\n      file.type === 'application/msword' ||\n      file.name.toLowerCase().endsWith('.doc')\n    );\n  }\n}\n\n/**\n * Formats DOCX content for AI consumption\n * @param result The parsed DOCX result\n * @param options Formatting options\n * @returns Formatted text representation of the DOCX\n */\nexport function docxToText(\n  result: DOCXParseResult,\n  options: {\n    includeSummary?: boolean;\n    includeStructure?: boolean;\n    includeProperties?: boolean;\n  } = {}\n): string {\n  // Default options\n  const includeSummary = options.includeSummary !== false;\n  // Make these false by default\n  const includeStructure = options.includeStructure === true;\n  const includeProperties = options.includeProperties === true;\n  \n  const lines: string[] = [];\n  \n  // Add the main text content\n  lines.push(result.text);\n  \n  // Add a brief summary if requested\n  if (includeSummary) {\n    lines.push('');\n    lines.push('--- Document Summary ---');\n    if (result.structure) {\n      lines.push(`Document contains approximately ${result.structure.paragraphs} paragraphs of text.`);\n      if (result.structure.tables > 0) {\n        lines.push(`Document includes ${result.structure.tables} tables.`);\n      }\n      if (result.structure.images > 0) {\n        lines.push(`Document contains ${result.structure.images} images (not included in text).`);\n      }\n    }\n  }\n  \n  // Add document structure information only if explicitly requested\n  if (includeStructure && result.structure) {\n    lines.push('');\n    lines.push('--- Document Structure ---');\n    lines.push(`Paragraphs: ${result.structure.paragraphs}`);\n    lines.push(`Tables: ${result.structure.tables}`);\n    lines.push(`Images: ${result.structure.images}`);\n    lines.push(`Sections: ${result.structure.sections}`);\n  }\n  \n  // Add document properties only if explicitly requested\n  if (includeProperties && result.properties) {\n    lines.push('');\n    lines.push('--- Document Properties ---');\n    for (const [key, value] of Object.entries(result.properties)) {\n      lines.push(`${key}: ${value}`);\n    }\n  }\n  \n  return lines.join('\\n');\n}\n\n/**\n * Extract text from a DOCX file\n * @param file DOCX file\n * @param options Parsing options\n * @returns Promise resolving to extracted text\n */\nexport async function extractTextFromDOCX(\n  file: File,\n  options: DOCXParseOptions = {}\n): Promise<string> {\n  try {\n    const result = await DOCXParser.parseFromFile(file, options);\n    return result.text;\n  } catch (error) {\n    console.error('Error extracting text from DOCX:', error);\n    return `Error extracting text from DOCX: ${error instanceof Error ? error.message : String(error)}`;\n  }\n}\n\n/**\n * Processes a DOCX file and returns both structured data and text representation\n * @param file The DOCX file to process\n * @param options Parsing and formatting options\n * @returns Promise resolving to processed DOCX data\n */\nexport async function processDOCXFile(\n  file: File,\n  options: DOCXParseOptions & {\n    textFormatting?: {\n      includeSummary?: boolean;\n      includeStructure?: boolean;\n      includeProperties?: boolean;\n    }\n  } = {}\n): Promise<{\n  parsed: DOCXParseResult;\n  text: string;\n  formattedText: string;\n  debugInfo: string[];\n}> {\n  const debugInfo: string[] = [];\n  \n  // Validate file\n  if (!file || (!DOCXParser.isValidDocxFile(file) && !DOCXParser.isValidDocFile(file))) {\n    throw new Error('Invalid file: Must be a DOC or DOCX file');\n  }\n  \n  debugInfo.push(`Processing document: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);\n  \n  try {\n    // Parse the DOCX file\n    debugInfo.push('Parsing document file...');\n    const parsed = await DOCXParser.parseFromFile(file, {\n      ...options,\n      debug: true // Force debug for internal use\n    });\n    \n    debugInfo.push(`Document parsed successfully: ${parsed.text.length} characters of text`);\n    \n    if (parsed.debugInfo) {\n      debugInfo.push(...parsed.debugInfo);\n    }\n    \n    // Get the raw text\n    const text = parsed.text;\n    \n    // Create formatted text for AI with minimal metadata by default\n    debugInfo.push('Creating formatted text for AI...');\n    const formattedText = docxToText(parsed, {\n      includeSummary: options.textFormatting?.includeSummary !== false,\n      includeStructure: options.textFormatting?.includeStructure === true,\n      includeProperties: options.textFormatting?.includeProperties === true\n    });\n    debugInfo.push(`Formatted text created: ${formattedText.length} characters`);\n    \n    return {\n      parsed,\n      text,\n      formattedText,\n      debugInfo\n    };\n  } catch (error) {\n    debugInfo.push(`Error: ${error instanceof Error ? error.message : String(error)}`);\n    throw error;\n  }\n} ","import * as Tesseract from 'tesseract.js';\n\n/**\n * Options for image parsing\n */\nexport interface ImageParseOptions {\n  /**\n   * Language for OCR (default: 'eng')\n   */\n  language?: string;\n  \n  /**\n   * Whether to include confidence scores (default: false)\n   */\n  includeConfidence?: boolean;\n  \n  /**\n   * Debug mode (default: false)\n   */\n  debug?: boolean;\n}\n\n/**\n * Result of image parsing\n */\nexport interface ImageParseResult {\n  /**\n   * The extracted text content\n   */\n  text: string;\n  \n  /**\n   * Image properties\n   */\n  properties?: {\n    width: number;\n    height: number;\n    format: string;\n    size: number;\n  };\n  \n  /**\n   * OCR confidence score (0-100)\n   */\n  confidence?: number;\n  \n  /**\n   * Any errors encountered during parsing\n   */\n  errors?: string[];\n  \n  /**\n   * Debug information\n   */\n  debugInfo?: string[];\n  \n  /**\n   * Whether the image contains meaningful text\n   */\n  hasText?: boolean;\n}\n\n/**\n * Parser for image files (JPEG, PNG)\n */\nexport class ImageParser {\n  /**\n   * Parse text from an image file\n   */\n  static async parseFromFile(file: File, options: ImageParseOptions = {}): Promise<ImageParseResult> {\n    const debugInfo: string[] = [];\n    if (options.debug) debugInfo.push(`Starting image parsing: ${file.name}`);\n    \n    try {\n      // Check if we're in a Chrome extension environment\n      const isExtension = typeof window !== 'undefined' && \n                         typeof (window as any).chrome !== 'undefined' && \n                         (window as any).chrome.runtime && \n                         (window as any).chrome.runtime.id;\n      \n      let text = '';\n      let confidence = 0;\n      \n      if (isExtension) {\n        // For extensions, use a simpler approach without OCR\n        // You could implement a basic image description here\n        text = `[Image: ${file.name} (${file.type}, ${Math.round(file.size/1024)} KB)]`;\n        confidence = 100; // Not real OCR confidence\n      } else {\n        // Create a blob URL from the file\n        const imageUrl = URL.createObjectURL(file);\n        \n        try {\n          // Use the simpler scheduler API instead of worker API\n          const result = await Tesseract.recognize(\n            imageUrl,\n            options.language || 'eng',\n            {\n              logger: options.debug ? m => {\n                if (typeof m === 'object') {\n                  debugInfo.push(`Tesseract: status=${m.status}, progress=${m.progress || 0}`);\n                } else {\n                  debugInfo.push(`Tesseract: ${String(m)}`);\n                }\n              } : undefined\n            }\n          );\n          \n          text = result.data.text;\n          confidence = result.data.confidence;\n        } finally {\n          // Always clean up the URL\n          URL.revokeObjectURL(imageUrl);\n        }\n      }\n      \n      // Get image properties\n      const properties = await this.extractImageProperties(file);\n      \n      // Clean the text\n      const cleanedText = this.cleanOcrText(text);\n      \n      // Determine if the image has meaningful text\n      const hasText = this.hasActualText(cleanedText, confidence);\n      \n      return {\n        text: cleanedText,\n        properties,\n        confidence,\n        hasText,\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    } catch (error) {\n      const errorMessage = (error as Error).message;\n      if (options.debug) debugInfo.push(`Error: ${errorMessage}`);\n      \n      return {\n        text: `[Error processing image: ${errorMessage}]`,\n        hasText: false,\n        errors: [errorMessage],\n        debugInfo: options.debug ? debugInfo : undefined\n      };\n    }\n  }\n  \n  /**\n   * Extract properties from an image file\n   */\n  private static async extractImageProperties(file: File): Promise<ImageParseResult['properties']> {\n    return new Promise((resolve) => {\n      const img = new Image();\n      const objectUrl = URL.createObjectURL(file);\n      \n      img.onload = () => {\n        URL.revokeObjectURL(objectUrl);\n        resolve({\n          width: img.width,\n          height: img.height,\n          format: file.type.split('/')[1].toUpperCase(),\n          size: file.size\n        });\n      };\n      \n      img.onerror = () => {\n        URL.revokeObjectURL(objectUrl);\n        resolve({\n          width: 0,\n          height: 0,\n          format: file.type.split('/')[1].toUpperCase(),\n          size: file.size\n        });\n      };\n      \n      img.src = objectUrl;\n    });\n  }\n  \n  /**\n   * Check if a file is a valid image file\n   */\n  static isValidImageFile(file: File): boolean {\n    return file.type === 'image/jpeg' || \n           file.type === 'image/png' || \n           file.type === 'image/jpg';\n  }\n  \n  /**\n   * Clean OCR text by removing non-text symbols and noise\n   * @param text Raw OCR text\n   * @returns Cleaned text\n   */\n  private static cleanOcrText(text: string): string {\n    if (!text || text.trim().length === 0) {\n      return '';\n    }\n    \n    // Remove common OCR noise patterns\n    let cleaned = text\n      // Remove strings of special characters\n      .replace(/[^\\w\\s.,;:!?'\"()[\\]{}#@%&*+-=/<>|]{2,}/g, ' ')\n      // Remove isolated special characters\n      .replace(/\\s[^\\w\\s.,;:!?'\"()[\\]{}#@%&*+-=/<>|]\\s/g, ' ')\n      // Normalize whitespace\n      .replace(/\\s+/g, ' ')\n      .trim();\n    \n    return cleaned;\n  }\n  \n  /**\n   * Determines if extracted text is meaningful or just OCR noise\n   * @param text The extracted text\n   * @param confidence OCR confidence score\n   * @returns Whether the text is meaningful\n   */\n  private static hasActualText(text: string, confidence?: number): boolean {\n    // If text is empty after cleaning, it has no meaningful content\n    const cleaned = this.cleanOcrText(text);\n    if (!cleaned) {\n      return false;\n    }\n    \n    // Count actual words (3+ letters) vs. total tokens\n    const tokens = cleaned.split(/\\s+/);\n    const actualWords = tokens.filter(token => /^[a-zA-Z]{3,}$/.test(token));\n    \n    // Calculate the ratio of actual words to total tokens\n    const wordRatio = tokens.length > 0 ? actualWords.length / tokens.length : 0;\n    \n    // Check for random character distribution (a sign of noise)\n    const letters = cleaned.replace(/[^a-zA-Z]/g, '');\n    const singleLetterCount = (cleaned.match(/\\s[a-zA-Z]\\s/g) || []).length;\n    const singleLetterRatio = letters.length > 0 ? singleLetterCount / letters.length : 0;\n    \n    // If confidence is very low, it's likely noise\n    if (confidence !== undefined && confidence < 40) {\n      return false;\n    }\n    \n    // Check for common OCR noise patterns\n    const hasRandomSymbols = /[^\\w\\s.,;:!?'\"()[\\]{}#@%&*+-=/<>|]{2,}/.test(text);\n    const hasTooManySpecialChars = (text.match(/[^\\w\\s]/g) || []).length > text.length * 0.3;\n    const hasTooManySingleChars = singleLetterRatio > 0.2;\n    const hasLowWordRatio = wordRatio < 0.3;\n    \n    // Your example had lots of single letters and special characters\n    if (hasRandomSymbols && hasTooManySpecialChars && (hasTooManySingleChars || hasLowWordRatio)) {\n      return false;\n    }\n    \n    // Require a minimum number of actual words\n    return actualWords.length >= 3;\n  }\n}\n\n/**\n * Formats image OCR results for AI consumption\n */\nexport function imageToText(\n  result: ImageParseResult,\n  options: {\n    includeSummary?: boolean;\n  } = {}\n): string {\n  // Default options\n  const includeSummary = options.includeSummary !== false;\n  \n  const lines: string[] = [];\n  \n  // If no text was found, return a simple message\n  if (!result.text || result.text.trim().length === 0) {\n    if (includeSummary) {\n      return 'This image does not contain any readable text.';\n    }\n    return '';\n  }\n  \n  // Add the main text content\n  lines.push(result.text);\n  \n  // Add a brief summary if requested\n  if (includeSummary && result.properties) {\n    lines.push('');\n    lines.push('--- Image Summary ---');\n    lines.push(`Image dimensions: ${result.properties.width}x${result.properties.height} pixels`);\n    lines.push(`Image format: ${result.properties.format}`);\n    lines.push(`Image size: ${Math.round(result.properties.size / 1024)} KB`);\n    \n    if (result.confidence !== undefined) {\n      lines.push(`OCR confidence: ${result.confidence.toFixed(2)}%`);\n    }\n  }\n  \n  return lines.join('\\n');\n}\n\n/**\n * Extract text from an image file\n */\nexport async function extractTextFromImage(\n  file: File,\n  options: ImageParseOptions = {}\n): Promise<string> {\n  const result = await ImageParser.parseFromFile(file, options);\n  return result.text;\n}\n\n/**\n * Process an image file and return various representations\n */\nexport async function processImageFile(\n  file: File,\n  options: ImageParseOptions & {\n    textFormatting?: {\n      includeSummary?: boolean;\n    }\n  } = {}\n): Promise<{\n  parsed: ImageParseResult;\n  text: string;\n  formattedText: string;\n  debugInfo: string[];\n}> {\n  const debugInfo: string[] = [];\n  \n  if (options.debug) {\n    debugInfo.push(`Processing image file: ${file.name}`);\n  }\n  \n  // Parse the image file\n  debugInfo.push('Parsing image file...');\n  const parsed = await ImageParser.parseFromFile(file, options);\n  \n  if (parsed.debugInfo) {\n    debugInfo.push(...parsed.debugInfo);\n  }\n  \n  // Extract raw text\n  debugInfo.push('Extracting raw text...');\n  const text = parsed.text;\n  \n  // Create formatted text for AI\n  debugInfo.push('Creating formatted text for AI...');\n  const formattedText = imageToText(parsed, {\n    includeSummary: options.textFormatting?.includeSummary !== false\n  });\n  \n  return {\n    parsed,\n    text,\n    formattedText,\n    debugInfo\n  };\n}"]}