@huggingface/transformers 4.0.0-next.5 → 4.0.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +12 -4
  2. package/dist/ort-wasm-simd-threaded.jsep.mjs +24 -24
  3. package/dist/transformers.js +2189 -1015
  4. package/dist/transformers.min.js +16 -16
  5. package/dist/transformers.node.cjs +2234 -1029
  6. package/dist/transformers.node.min.cjs +20 -20
  7. package/dist/transformers.node.min.mjs +20 -20
  8. package/dist/transformers.node.mjs +2194 -1017
  9. package/dist/transformers.web.js +2175 -1001
  10. package/dist/transformers.web.min.js +18 -18
  11. package/package.json +4 -4
  12. package/src/backends/onnx.js +77 -58
  13. package/src/backends/utils/cacheWasm.js +22 -43
  14. package/src/cache_utils.js +62 -0
  15. package/src/configs.js +32 -5
  16. package/src/env.js +36 -6
  17. package/src/image_processors_utils.js +3 -3
  18. package/src/models/auto/modeling_auto.js +14 -1
  19. package/src/models/chatterbox/modeling_chatterbox.js +1 -1
  20. package/src/models/detr/image_processing_detr.js +1 -1
  21. package/src/models/feature_extractors.js +2 -0
  22. package/src/models/gemma3n/modeling_gemma3n.js +2 -0
  23. package/src/models/granite_speech/feature_extraction_granite_speech.js +58 -0
  24. package/src/models/granite_speech/modeling_granite_speech.js +5 -0
  25. package/src/models/granite_speech/processing_granite_speech.js +62 -0
  26. package/src/models/grounding_dino/image_processing_grounding_dino.js +1 -1
  27. package/src/models/idefics3/modeling_idefics3.js +5 -32
  28. package/src/models/image_processors.js +1 -0
  29. package/src/models/lfm2_vl/image_processing_lfm2_vl.js +305 -0
  30. package/src/models/lfm2_vl/modeling_lfm2_vl.js +13 -0
  31. package/src/models/lfm2_vl/processing_lfm2_vl.js +77 -0
  32. package/src/models/llava/modeling_llava.js +1 -1
  33. package/src/models/mistral3/modeling_mistral3.js +2 -2
  34. package/src/models/modeling_utils.js +234 -292
  35. package/src/models/models.js +9 -0
  36. package/src/models/olmo_hybrid/modeling_olmo_hybrid.js +5 -0
  37. package/src/models/paligemma/modeling_paligemma.js +2 -25
  38. package/src/models/processors.js +3 -0
  39. package/src/models/qwen2_5_vl/modeling_qwen2_5_vl.js +5 -1
  40. package/src/models/qwen2_moe/modeling_qwen2_moe.js +5 -0
  41. package/src/models/qwen2_vl/image_processing_qwen2_vl.js +1 -41
  42. package/src/models/qwen2_vl/modeling_qwen2_vl.js +36 -3
  43. package/src/models/qwen3_5/modeling_qwen3_5.js +1 -0
  44. package/src/models/qwen3_5_moe/modeling_qwen3_5_moe.js +2 -1
  45. package/src/models/qwen3_moe/modeling_qwen3_moe.js +5 -0
  46. package/src/models/qwen3_next/modeling_qwen3_next.js +5 -0
  47. package/src/models/qwen3_vl/modeling_qwen3_vl.js +2 -1
  48. package/src/models/qwen3_vl_moe/modeling_qwen3_vl_moe.js +4 -0
  49. package/src/models/registry.js +39 -4
  50. package/src/models/sam/image_processing_sam.js +1 -1
  51. package/src/models/session.js +17 -6
  52. package/src/models/smolvlm/modeling_smolvlm.js +7 -0
  53. package/src/models/ultravox/modeling_ultravox.js +1 -3
  54. package/src/models/voxtral/modeling_voxtral.js +3 -0
  55. package/src/models/voxtral_realtime/feature_extraction_voxtral_realtime.js +71 -0
  56. package/src/models/voxtral_realtime/modeling_voxtral_realtime.js +239 -0
  57. package/src/models/voxtral_realtime/processing_voxtral_realtime.js +113 -0
  58. package/src/models/whisper/feature_extraction_whisper.js +2 -12
  59. package/src/pipelines/index.js +2 -84
  60. package/src/pipelines.js +40 -77
  61. package/src/transformers.js +2 -0
  62. package/src/utils/audio.js +18 -2
  63. package/src/utils/cache/CrossOriginStorageCache.js +251 -0
  64. package/src/utils/cache/FileCache.js +128 -0
  65. package/src/utils/cache/cross-origin-storage.d.ts +38 -0
  66. package/src/utils/cache.js +8 -3
  67. package/src/utils/hub/{files.js → FileResponse.js} +0 -105
  68. package/src/utils/hub/utils.js +35 -1
  69. package/src/utils/hub.js +6 -5
  70. package/src/utils/image.js +12 -13
  71. package/src/utils/lru_cache.js +67 -0
  72. package/src/utils/memoize_promise.js +45 -0
  73. package/src/utils/model_registry/ModelRegistry.js +70 -23
  74. package/src/utils/model_registry/get_file_metadata.js +14 -2
  75. package/src/utils/model_registry/get_model_files.js +63 -78
  76. package/src/utils/model_registry/get_pipeline_files.js +15 -24
  77. package/src/utils/model_registry/is_cached.js +81 -4
  78. package/src/utils/tensor.js +18 -2
  79. package/types/backends/onnx.d.ts.map +1 -1
  80. package/types/backends/utils/cacheWasm.d.ts +3 -17
  81. package/types/backends/utils/cacheWasm.d.ts.map +1 -1
  82. package/types/cache_utils.d.ts +29 -0
  83. package/types/cache_utils.d.ts.map +1 -0
  84. package/types/configs.d.ts.map +1 -1
  85. package/types/env.d.ts +18 -3
  86. package/types/env.d.ts.map +1 -1
  87. package/types/image_processors_utils.d.ts +17 -1
  88. package/types/image_processors_utils.d.ts.map +1 -1
  89. package/types/models/auto/modeling_auto.d.ts +6 -0
  90. package/types/models/auto/modeling_auto.d.ts.map +1 -1
  91. package/types/models/detr/image_processing_detr.d.ts +1 -1
  92. package/types/models/feature_extractors.d.ts +2 -0
  93. package/types/models/gemma3n/modeling_gemma3n.d.ts +2 -0
  94. package/types/models/gemma3n/modeling_gemma3n.d.ts.map +1 -1
  95. package/types/models/granite_speech/feature_extraction_granite_speech.d.ts +16 -0
  96. package/types/models/granite_speech/feature_extraction_granite_speech.d.ts.map +1 -0
  97. package/types/models/granite_speech/modeling_granite_speech.d.ts +4 -0
  98. package/types/models/granite_speech/modeling_granite_speech.d.ts.map +1 -0
  99. package/types/models/granite_speech/processing_granite_speech.d.ts +19 -0
  100. package/types/models/granite_speech/processing_granite_speech.d.ts.map +1 -0
  101. package/types/models/grounding_dino/image_processing_grounding_dino.d.ts +1 -1
  102. package/types/models/idefics3/modeling_idefics3.d.ts +2 -18
  103. package/types/models/idefics3/modeling_idefics3.d.ts.map +1 -1
  104. package/types/models/image_processors.d.ts +1 -0
  105. package/types/models/lfm2_vl/image_processing_lfm2_vl.d.ts +41 -0
  106. package/types/models/lfm2_vl/image_processing_lfm2_vl.d.ts.map +1 -0
  107. package/types/models/lfm2_vl/modeling_lfm2_vl.d.ts +4 -0
  108. package/types/models/lfm2_vl/modeling_lfm2_vl.d.ts.map +1 -0
  109. package/types/models/lfm2_vl/processing_lfm2_vl.d.ts +18 -0
  110. package/types/models/lfm2_vl/processing_lfm2_vl.d.ts.map +1 -0
  111. package/types/models/mistral3/modeling_mistral3.d.ts +2 -2
  112. package/types/models/mistral3/modeling_mistral3.d.ts.map +1 -1
  113. package/types/models/modeling_utils.d.ts +44 -24
  114. package/types/models/modeling_utils.d.ts.map +1 -1
  115. package/types/models/models.d.ts +9 -0
  116. package/types/models/olmo_hybrid/modeling_olmo_hybrid.d.ts +8 -0
  117. package/types/models/olmo_hybrid/modeling_olmo_hybrid.d.ts.map +1 -0
  118. package/types/models/paligemma/modeling_paligemma.d.ts +2 -8
  119. package/types/models/paligemma/modeling_paligemma.d.ts.map +1 -1
  120. package/types/models/processors.d.ts +3 -0
  121. package/types/models/qwen2_5_vl/modeling_qwen2_5_vl.d.ts +3 -0
  122. package/types/models/qwen2_5_vl/modeling_qwen2_5_vl.d.ts.map +1 -1
  123. package/types/models/qwen2_moe/modeling_qwen2_moe.d.ts +8 -0
  124. package/types/models/qwen2_moe/modeling_qwen2_moe.d.ts.map +1 -0
  125. package/types/models/qwen2_vl/image_processing_qwen2_vl.d.ts.map +1 -1
  126. package/types/models/qwen2_vl/modeling_qwen2_vl.d.ts +2 -0
  127. package/types/models/qwen2_vl/modeling_qwen2_vl.d.ts.map +1 -1
  128. package/types/models/qwen3_5/modeling_qwen3_5.d.ts +2 -0
  129. package/types/models/qwen3_5/modeling_qwen3_5.d.ts.map +1 -1
  130. package/types/models/qwen3_5_moe/modeling_qwen3_5_moe.d.ts +3 -0
  131. package/types/models/qwen3_5_moe/modeling_qwen3_5_moe.d.ts.map +1 -1
  132. package/types/models/qwen3_moe/modeling_qwen3_moe.d.ts +8 -0
  133. package/types/models/qwen3_moe/modeling_qwen3_moe.d.ts.map +1 -0
  134. package/types/models/qwen3_next/modeling_qwen3_next.d.ts +8 -0
  135. package/types/models/qwen3_next/modeling_qwen3_next.d.ts.map +1 -0
  136. package/types/models/qwen3_vl/modeling_qwen3_vl.d.ts +3 -0
  137. package/types/models/qwen3_vl/modeling_qwen3_vl.d.ts.map +1 -1
  138. package/types/models/qwen3_vl_moe/modeling_qwen3_vl_moe.d.ts +7 -0
  139. package/types/models/qwen3_vl_moe/modeling_qwen3_vl_moe.d.ts.map +1 -0
  140. package/types/models/registry.d.ts +2 -1
  141. package/types/models/registry.d.ts.map +1 -1
  142. package/types/models/sam/image_processing_sam.d.ts +1 -1
  143. package/types/models/session.d.ts +3 -2
  144. package/types/models/session.d.ts.map +1 -1
  145. package/types/models/smolvlm/modeling_smolvlm.d.ts +8 -0
  146. package/types/models/smolvlm/modeling_smolvlm.d.ts.map +1 -0
  147. package/types/models/ultravox/modeling_ultravox.d.ts +0 -2
  148. package/types/models/ultravox/modeling_ultravox.d.ts.map +1 -1
  149. package/types/models/voxtral/modeling_voxtral.d.ts +4 -0
  150. package/types/models/voxtral/modeling_voxtral.d.ts.map +1 -0
  151. package/types/models/voxtral_realtime/feature_extraction_voxtral_realtime.d.ts +28 -0
  152. package/types/models/voxtral_realtime/feature_extraction_voxtral_realtime.d.ts.map +1 -0
  153. package/types/models/voxtral_realtime/modeling_voxtral_realtime.d.ts +17 -0
  154. package/types/models/voxtral_realtime/modeling_voxtral_realtime.d.ts.map +1 -0
  155. package/types/models/voxtral_realtime/processing_voxtral_realtime.d.ts +44 -0
  156. package/types/models/voxtral_realtime/processing_voxtral_realtime.d.ts.map +1 -0
  157. package/types/models/whisper/feature_extraction_whisper.d.ts.map +1 -1
  158. package/types/pipelines/index.d.ts +0 -34
  159. package/types/pipelines/index.d.ts.map +1 -1
  160. package/types/pipelines.d.ts.map +1 -1
  161. package/types/transformers.d.ts +1 -0
  162. package/types/transformers.d.ts.map +1 -1
  163. package/types/utils/audio.d.ts +5 -2
  164. package/types/utils/audio.d.ts.map +1 -1
  165. package/types/utils/cache/CrossOriginStorageCache.d.ts +120 -0
  166. package/types/utils/cache/CrossOriginStorageCache.d.ts.map +1 -0
  167. package/types/utils/cache/FileCache.d.ts +39 -0
  168. package/types/utils/cache/FileCache.d.ts.map +1 -0
  169. package/types/utils/cache.d.ts +4 -4
  170. package/types/utils/cache.d.ts.map +1 -1
  171. package/types/utils/dtypes.d.ts +1 -1
  172. package/types/utils/hub/{files.d.ts → FileResponse.d.ts} +1 -38
  173. package/types/utils/hub/FileResponse.d.ts.map +1 -0
  174. package/types/utils/hub/utils.d.ts +17 -2
  175. package/types/utils/hub/utils.d.ts.map +1 -1
  176. package/types/utils/hub.d.ts +7 -7
  177. package/types/utils/hub.d.ts.map +1 -1
  178. package/types/utils/image.d.ts +1 -1
  179. package/types/utils/image.d.ts.map +1 -1
  180. package/types/utils/lru_cache.d.ts +38 -0
  181. package/types/utils/lru_cache.d.ts.map +1 -0
  182. package/types/utils/memoize_promise.d.ts +14 -0
  183. package/types/utils/memoize_promise.d.ts.map +1 -0
  184. package/types/utils/model_registry/ModelRegistry.d.ts +66 -6
  185. package/types/utils/model_registry/ModelRegistry.d.ts.map +1 -1
  186. package/types/utils/model_registry/get_file_metadata.d.ts.map +1 -1
  187. package/types/utils/model_registry/get_model_files.d.ts +1 -0
  188. package/types/utils/model_registry/get_model_files.d.ts.map +1 -1
  189. package/types/utils/model_registry/get_pipeline_files.d.ts +2 -1
  190. package/types/utils/model_registry/get_pipeline_files.d.ts.map +1 -1
  191. package/types/utils/model_registry/is_cached.d.ts +47 -4
  192. package/types/utils/model_registry/is_cached.d.ts.map +1 -1
  193. package/types/utils/tensor.d.ts.map +1 -1
  194. package/src/utils/data-structures.js +0 -572
  195. package/types/utils/data-structures.d.ts +0 -294
  196. package/types/utils/data-structures.d.ts.map +0 -1
  197. package/types/utils/hub/files.d.ts.map +0 -1
@@ -1,5 +1,4 @@
1
1
  import fs from 'node:fs';
2
- import path from 'node:path';
3
2
 
4
3
  /**
5
4
  * Mapping from file extensions to MIME types.
@@ -120,107 +119,3 @@ export class FileResponse {
120
119
  return JSON.parse(await this.text());
121
120
  }
122
121
  }
123
-
124
- /**
125
- * File system cache implementation that implements the CacheInterface.
126
- * Provides `match` and `put` methods compatible with the Web Cache API.
127
- */
128
- export class FileCache {
129
- /**
130
- * Instantiate a `FileCache` object.
131
- * @param {string} path
132
- */
133
- constructor(path) {
134
- this.path = path;
135
- }
136
-
137
- /**
138
- * Checks whether the given request is in the cache.
139
- * @param {string} request
140
- * @returns {Promise<FileResponse | undefined>}
141
- */
142
- async match(request) {
143
- let filePath = path.join(this.path, request);
144
- let file = new FileResponse(filePath);
145
-
146
- if (file.exists) {
147
- return file;
148
- } else {
149
- return undefined;
150
- }
151
- }
152
-
153
- /**
154
- * Adds the given response to the cache.
155
- * @param {string} request
156
- * @param {Response} response
157
- * @param {(data: {progress: number, loaded: number, total: number}) => void} [progress_callback] Optional.
158
- * The function to call with progress updates
159
- * @returns {Promise<void>}
160
- */
161
- async put(request, response, progress_callback = undefined) {
162
- let filePath = path.join(this.path, request);
163
-
164
- try {
165
- const contentLength = response.headers.get('Content-Length');
166
- const total = parseInt(contentLength ?? '0');
167
- let loaded = 0;
168
-
169
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
170
- const fileStream = fs.createWriteStream(filePath);
171
- const reader = response.body.getReader();
172
-
173
- while (true) {
174
- const { done, value } = await reader.read();
175
- if (done) {
176
- break;
177
- }
178
-
179
- await new Promise((resolve, reject) => {
180
- fileStream.write(value, (err) => {
181
- if (err) {
182
- reject(err);
183
- return;
184
- }
185
- resolve();
186
- });
187
- });
188
-
189
- loaded += value.length;
190
- const progress = total ? (loaded / total) * 100 : 0;
191
-
192
- progress_callback?.({ progress, loaded, total });
193
- }
194
-
195
- fileStream.close();
196
- } catch (error) {
197
- // Clean up the file if an error occurred during download
198
- try {
199
- await fs.promises.unlink(filePath);
200
- } catch {}
201
- throw error;
202
- }
203
- }
204
-
205
- /**
206
- * Deletes the cache entry for the given request.
207
- * @param {string} request
208
- * @returns {Promise<boolean>} A Promise that resolves to `true` if the cache entry was deleted, `false` otherwise.
209
- */
210
- async delete(request) {
211
- let filePath = path.join(this.path, request);
212
-
213
- try {
214
- await fs.promises.unlink(filePath);
215
- return true;
216
- } catch (error) {
217
- // File doesn't exist or couldn't be deleted
218
- return false;
219
- }
220
- }
221
-
222
- // TODO add the rest?
223
- // addAll(requests: RequestInfo[]): Promise<void>;
224
- // keys(request?: RequestInfo | URL, options?: CacheQueryOptions): Promise<ReadonlyArray<Request>>;
225
- // matchAll(request?: RequestInfo | URL, options?: CacheQueryOptions): Promise<ReadonlyArray<Response>>;
226
- }
@@ -80,7 +80,7 @@ export function handleError(status, remoteURL, fatal) {
80
80
  /**
81
81
  * Read and track progress when reading a Response object
82
82
  *
83
- * @param {Response|import('./files.js').FileResponse} response The Response object to read
83
+ * @param {Response|import('./FileResponse.js').FileResponse} response The Response object to read
84
84
  * @param {(data: {progress: number, loaded: number, total: number}) => void} progress_callback The function to call with progress updates
85
85
  * @param {number} [expectedSize] The expected size of the file (used when content-length header is missing)
86
86
  * @returns {Promise<Uint8Array>} A Promise that resolves with the Uint8Array buffer
@@ -132,3 +132,37 @@ export async function readResponse(response, progress_callback, expectedSize) {
132
132
 
133
133
  return buffer;
134
134
  }
135
+
136
+ /**
137
+ * Checks if the given URL is a blob URL (created via URL.createObjectURL).
138
+ * Blob URLs should not be cached as they are temporary in-memory references.
139
+ * @param {string} url - The URL to check.
140
+ * @returns {boolean} True if the URL is a blob URL, false otherwise.
141
+ */
142
+ export function isBlobURL(url) {
143
+ return isValidUrl(url, ['blob:']);
144
+ }
145
+
146
+ /**
147
+ * Converts any URL to an absolute URL if needed.
148
+ * If the URL is already absolute (http://, https://, or blob:), returns it unchanged (handled by new URL(...)).
149
+ * Otherwise, resolves it relative to the current page location (browser) or module location (Node/Bun/Deno).
150
+ * @param {string} url - The URL to convert (can be relative or absolute).
151
+ * @returns {string} The absolute URL.
152
+ */
153
+ export function toAbsoluteURL(url) {
154
+ let baseURL;
155
+
156
+ if (typeof location !== 'undefined' && location.href) {
157
+ // Browser environment: use location.href
158
+ baseURL = location.href;
159
+ } else if (typeof import.meta !== 'undefined' && import.meta.url) {
160
+ // Node.js/Bun/Deno module environment: use import.meta.url
161
+ baseURL = import.meta.url;
162
+ } else {
163
+ // Fallback: if no base is available, return the URL unchanged
164
+ return url;
165
+ }
166
+
167
+ return new URL(url, baseURL).href;
168
+ }
package/src/utils/hub.js CHANGED
@@ -6,7 +6,8 @@
6
6
 
7
7
  import { apis, env } from '../env.js';
8
8
  import { dispatchCallback } from './core.js';
9
- import { FileResponse, FileCache } from './hub/files.js';
9
+ import { FileResponse } from './hub/FileResponse.js';
10
+ import { FileCache } from './cache/FileCache.js';
10
11
  import { handleError, isValidUrl, pathJoin, isValidHfModelId, readResponse } from './hub/utils.js';
11
12
  import { getCache, tryCache } from './cache.js';
12
13
  import { get_file_metadata } from './model_registry/get_file_metadata.js';
@@ -39,7 +40,7 @@ export { MAX_EXTERNAL_DATA_CHUNKS } from './hub/constants.js';
39
40
  * @typedef {Object} ModelSpecificPretrainedOptions Options for loading a pretrained model.
40
41
  * @property {string} [subfolder='onnx'] In case the relevant files are located inside a subfolder of the model repo on huggingface.co,
41
42
  * you can specify the folder name here.
42
- * @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.
43
+ * @property {string} [model_file_name=null] If specified, load the model with this name (excluding the dtype and .onnx suffixes). Currently only valid for encoder- or decoder-only models.
43
44
  * @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.
44
45
  * @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.
45
46
  * @property {ExternalData|Record<string, ExternalData>} [use_external_data_format=false] Whether to load the model using the external data format (used for models >= 2GB in size).
@@ -160,7 +161,7 @@ export function buildResourcePaths(path_or_repo_id, filename, options = {}, cach
160
161
  * @param {import('./cache.js').CacheInterface | null} cache The cache instance to check.
161
162
  * @param {string} localPath The local path to try first.
162
163
  * @param {string} proposedCacheKey The proposed cache key to try second.
163
- * @returns {Promise<Response|import('./hub/files.js').FileResponse|undefined|string>}
164
+ * @returns {Promise<Response|import('./hub/FileResponse.js').FileResponse|undefined|string>}
164
165
  * The cached response if found, undefined otherwise.
165
166
  */
166
167
  export async function checkCachedResource(cache, localPath, proposedCacheKey) {
@@ -182,7 +183,7 @@ export async function checkCachedResource(cache, localPath, proposedCacheKey) {
182
183
  * @param {string} filename The name of the file to cache.
183
184
  * @param {import('./cache.js').CacheInterface} cache The cache instance to store in.
184
185
  * @param {string} cacheKey The cache key to use.
185
- * @param {Response|import('./hub/files.js').FileResponse} response The response to cache.
186
+ * @param {Response|import('./hub/FileResponse.js').FileResponse} response The response to cache.
186
187
  * @param {Uint8Array} [result] The result buffer if already read.
187
188
  * @param {PretrainedOptions} [options] Options containing progress callback and context for progress updates.
188
189
  * @returns {Promise<void>}
@@ -259,7 +260,7 @@ export async function loadResourceFile(
259
260
  // Whether to cache the final response in the end.
260
261
  let toCacheResponse = false;
261
262
 
262
- /** @type {Response|import('./hub/files.js').FileResponse|undefined|string} */
263
+ /** @type {Response|import('./hub/FileResponse.js').FileResponse|undefined|string} */
263
264
  let response;
264
265
 
265
266
  // Check cache
@@ -20,12 +20,11 @@ import { logger } from './logger.js';
20
20
  let createCanvasFunction;
21
21
  let ImageDataClass;
22
22
  let loadImageFunction;
23
- const IS_BROWSER_OR_WEBWORKER = apis.IS_BROWSER_ENV || apis.IS_WEBWORKER_ENV;
24
- if (IS_BROWSER_OR_WEBWORKER) {
23
+ if (apis.IS_WEB_ENV) {
25
24
  // Running in browser or web-worker
26
25
  createCanvasFunction = (/** @type {number} */ width, /** @type {number} */ height) => {
27
26
  if (!self.OffscreenCanvas) {
28
- throw new Error('OffscreenCanvas not supported by this browser.');
27
+ throw new Error('OffscreenCanvas not supported by this environment.');
29
28
  }
30
29
  return new self.OffscreenCanvas(width, height);
31
30
  };
@@ -134,7 +133,7 @@ export class RawImage {
134
133
  * @returns {RawImage} The image object.
135
134
  */
136
135
  static fromCanvas(canvas) {
137
- if (!IS_BROWSER_OR_WEBWORKER) {
136
+ if (!apis.IS_WEB_ENV) {
138
137
  throw new Error('fromCanvas() is only supported in browser environments.');
139
138
  }
140
139
 
@@ -165,7 +164,7 @@ export class RawImage {
165
164
  * @returns {Promise<RawImage>} The image object.
166
165
  */
167
166
  static async fromBlob(blob) {
168
- if (IS_BROWSER_OR_WEBWORKER) {
167
+ if (apis.IS_WEB_ENV) {
169
168
  // Running in environment with canvas
170
169
  const img = await loadImageFunction(blob);
171
170
 
@@ -379,7 +378,7 @@ export class RawImage {
379
378
  height = (width / this.width) * this.height;
380
379
  }
381
380
 
382
- if (IS_BROWSER_OR_WEBWORKER) {
381
+ if (apis.IS_WEB_ENV) {
383
382
  // TODO use `resample` in browser environment
384
383
 
385
384
  // Store number of channels before resizing
@@ -453,7 +452,7 @@ export class RawImage {
453
452
  return this;
454
453
  }
455
454
 
456
- if (IS_BROWSER_OR_WEBWORKER) {
455
+ if (apis.IS_WEB_ENV) {
457
456
  // Store number of channels before padding
458
457
  const numChannels = this.channels;
459
458
 
@@ -495,7 +494,7 @@ export class RawImage {
495
494
  const crop_width = x_max - x_min + 1;
496
495
  const crop_height = y_max - y_min + 1;
497
496
 
498
- if (IS_BROWSER_OR_WEBWORKER) {
497
+ if (apis.IS_WEB_ENV) {
499
498
  // Store number of channels before resizing
500
499
  const numChannels = this.channels;
501
500
 
@@ -542,7 +541,7 @@ export class RawImage {
542
541
  const width_offset = (this.width - crop_width) / 2;
543
542
  const height_offset = (this.height - crop_height) / 2;
544
543
 
545
- if (IS_BROWSER_OR_WEBWORKER) {
544
+ if (apis.IS_WEB_ENV) {
546
545
  // Store number of channels before resizing
547
546
  const numChannels = this.channels;
548
547
 
@@ -650,7 +649,7 @@ export class RawImage {
650
649
  }
651
650
 
652
651
  async toBlob(type = 'image/png', quality = 1) {
653
- if (!IS_BROWSER_OR_WEBWORKER) {
652
+ if (!apis.IS_WEB_ENV) {
654
653
  throw new Error('toBlob() is only supported in browser environments.');
655
654
  }
656
655
 
@@ -673,7 +672,7 @@ export class RawImage {
673
672
  }
674
673
 
675
674
  toCanvas() {
676
- if (!IS_BROWSER_OR_WEBWORKER) {
675
+ if (!apis.IS_WEB_ENV) {
677
676
  throw new Error('toCanvas() is only supported in browser environments.');
678
677
  }
679
678
 
@@ -774,7 +773,7 @@ export class RawImage {
774
773
  * @returns {Promise<void>}
775
774
  */
776
775
  async save(path) {
777
- if (IS_BROWSER_OR_WEBWORKER) {
776
+ if (apis.IS_WEB_ENV) {
778
777
  if (apis.IS_WEBWORKER_ENV) {
779
778
  throw new Error('Unable to save an image from a Web Worker.');
780
779
  }
@@ -799,7 +798,7 @@ export class RawImage {
799
798
  * @returns {import('sharp').Sharp} The Sharp instance.
800
799
  */
801
800
  toSharp() {
802
- if (IS_BROWSER_OR_WEBWORKER) {
801
+ if (apis.IS_WEB_ENV) {
803
802
  throw new Error('toSharp() is only supported in server-side environments.');
804
803
  }
805
804
 
@@ -0,0 +1,67 @@
1
+ /**
2
+ * A simple Least Recently Used (LRU) cache implementation in JavaScript.
3
+ * This cache stores key-value pairs and evicts the least recently used item
4
+ * when the capacity is exceeded.
5
+ */
6
+ export class LRUCache {
7
+ /** @type {number} */
8
+ #capacity;
9
+
10
+ /** @type {Map<any, any>} */
11
+ #cache;
12
+
13
+ /**
14
+ * Creates an LRUCache instance.
15
+ * @param {number} capacity The maximum number of items the cache can hold.
16
+ */
17
+ constructor(capacity) {
18
+ this.#capacity = capacity;
19
+ this.#cache = new Map();
20
+ }
21
+
22
+ /**
23
+ * Retrieves the value associated with the given key and marks the key as recently used.
24
+ * @param {any} key The key to retrieve.
25
+ * @returns {any} The value associated with the key, or undefined if the key does not exist.
26
+ */
27
+ get(key) {
28
+ if (!this.#cache.has(key)) return undefined;
29
+ const value = this.#cache.get(key);
30
+ this.#cache.delete(key);
31
+ this.#cache.set(key, value);
32
+ return value;
33
+ }
34
+
35
+ /**
36
+ * Inserts or updates the key-value pair in the cache.
37
+ * If the key already exists, it is updated and marked as recently used.
38
+ * If the cache exceeds its capacity, the least recently used item is evicted.
39
+ * @param {any} key The key to add or update.
40
+ * @param {any} value The value to associate with the key.
41
+ */
42
+ put(key, value) {
43
+ if (this.#cache.has(key)) {
44
+ this.#cache.delete(key);
45
+ }
46
+ this.#cache.set(key, value);
47
+ if (this.#cache.size > this.#capacity) {
48
+ this.#cache.delete(this.#cache.keys().next().value);
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Removes the entry for the given key from the cache.
54
+ * @param {any} key The key to delete.
55
+ * @returns {boolean} `true` if the entry existed and was removed, `false` otherwise.
56
+ */
57
+ delete(key) {
58
+ return this.#cache.delete(key);
59
+ }
60
+
61
+ /**
62
+ * Clears the cache.
63
+ */
64
+ clear() {
65
+ this.#cache.clear();
66
+ }
67
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @file Utility for memoizing promises by key.
3
+ *
4
+ * Ensures that a given async operation is only initiated once per key.
5
+ * Subsequent calls with the same key return the same pending or resolved promise.
6
+ * Rejected promises are evicted from the cache so callers can retry.
7
+ *
8
+ * The cache is bounded by `MAX_CACHE_SIZE`. When the limit is exceeded, the
9
+ * least-recently-used entry is evicted.
10
+ */
11
+
12
+ import { LRUCache } from './lru_cache.js';
13
+
14
+ const MAX_CACHE_SIZE = 100;
15
+
16
+ /** @type {LRUCache} */
17
+ const cache = new LRUCache(MAX_CACHE_SIZE);
18
+
19
+ /**
20
+ * Returns the cached promise for `key`, or calls `factory` to create one and caches it.
21
+ * Subsequent calls with the same key return the same promise whether it is still
22
+ * pending or already resolved, so the factory is never invoked more than once per key.
23
+ * If the promise rejects, the entry is removed from the cache so the operation can be retried.
24
+ *
25
+ * @template T
26
+ * @param {string} key A unique identifier for this async operation.
27
+ * @param {() => Promise<T>} factory A function that returns the promise to memoize.
28
+ * Only called when no entry exists for `key`.
29
+ * @returns {Promise<T>}
30
+ */
31
+ export function memoizePromise(key, factory) {
32
+ const cached = cache.get(key);
33
+ if (cached !== undefined) {
34
+ return cached;
35
+ }
36
+ const promise = factory().then(
37
+ (value) => value,
38
+ (err) => {
39
+ cache.delete(key);
40
+ return Promise.reject(err);
41
+ },
42
+ );
43
+ cache.put(key, promise);
44
+ return promise;
45
+ }
@@ -49,8 +49,12 @@
49
49
  * const modelId = "onnx-community/Qwen3-0.6B-ONNX";
50
50
  * const options = { dtype: "q4" };
51
51
  *
52
- * // Check if the model is cached (probably false)
53
- * let cacheStatus = await ModelRegistry.is_cached(modelId, options);
52
+ * // Quickly check if the model is cached (probably false)
53
+ * let cached = await ModelRegistry.is_cached(modelId, options);
54
+ * console.log(cached); // false
55
+ *
56
+ * // Get per-file cache detail
57
+ * let cacheStatus = await ModelRegistry.is_cached_files(modelId, options);
54
58
  * console.log(cacheStatus);
55
59
  * // {
56
60
  * // allCached: false,
@@ -66,12 +70,8 @@
66
70
  * console.log(output[0].generated_text.at(-1).content); // <think>...</think>\n\nThe capital of France is **Paris**.
67
71
  *
68
72
  * // Check if the model is cached (should be true now)
69
- * cacheStatus = await ModelRegistry.is_cached(modelId, options);
70
- * console.log(cacheStatus);
71
- * // {
72
- * // allCached: true,
73
- * // files: [ { file: 'config.json', cached: true }, { file: 'onnx/model_q4.onnx', cached: true }, { file: 'generation_config.json', cached: true }, { file: 'tokenizer.json', cached: true }, { file: 'tokenizer_config.json', cached: true } ]
74
- * // }
73
+ * cached = await ModelRegistry.is_cached(modelId, options);
74
+ * console.log(cached); // true
75
75
  *
76
76
  * // Clear the cache
77
77
  * const clearResult = await ModelRegistry.clear_cache(modelId, options);
@@ -83,12 +83,8 @@
83
83
  * // }
84
84
  *
85
85
  * // Check if the model is cached (should be false again)
86
- * cacheStatus = await ModelRegistry.is_cached(modelId, options);
87
- * console.log(cacheStatus);
88
- * // {
89
- * // allCached: false,
90
- * // files: [ { file: 'config.json', cached: true }, { file: 'onnx/model_q4.onnx', cached: false }, { file: 'generation_config.json', cached: false }, { file: 'tokenizer.json', cached: false }, { file: 'tokenizer_config.json', cached: false } ]
91
- * // }
86
+ * cached = await ModelRegistry.is_cached(modelId, options);
87
+ * console.log(cached); // false
92
88
  * ```
93
89
  *
94
90
  * @module utils/model_registry
@@ -99,7 +95,7 @@ import { get_pipeline_files } from './get_pipeline_files.js';
99
95
  import { get_model_files } from './get_model_files.js';
100
96
  import { get_tokenizer_files } from './get_tokenizer_files.js';
101
97
  import { get_processor_files } from './get_processor_files.js';
102
- import { is_cached, is_pipeline_cached } from './is_cached.js';
98
+ import { is_cached, is_cached_files, is_pipeline_cached, is_pipeline_cached_files } from './is_cached.js';
103
99
  import { get_file_metadata } from './get_file_metadata.js';
104
100
  import { clear_cache, clear_pipeline_cache } from './clear_cache.js';
105
101
 
@@ -198,27 +194,31 @@ export class ModelRegistry {
198
194
  }
199
195
 
200
196
  /**
201
- * Check if a model and all its required files are cached.
197
+ * Quickly checks if a model is fully cached by verifying `config.json` is present,
198
+ * then confirming all required files are cached.
199
+ * Returns a plain boolean — use `is_cached_files` if you need per-file detail.
202
200
  *
203
201
  * @param {string} modelId - The model id
204
202
  * @param {Object} [options] - Optional parameters
203
+ * @param {string} [options.cache_dir] - Custom cache directory
204
+ * @param {string} [options.revision] - Model revision (default: 'main')
205
+ * @param {import('../../configs.js').PretrainedConfig} [options.config] - Pre-loaded config
205
206
  * @param {import('../dtypes.js').DataType|Record<string, import('../dtypes.js').DataType>} [options.dtype=null] - Override dtype
206
207
  * @param {import('../devices.js').DeviceType|Record<string, import('../devices.js').DeviceType>} [options.device=null] - Override device
207
- * @returns {Promise<import('./is_cached.js').CacheCheckResult>} Object with allCached boolean and files array with cache status
208
+ * @returns {Promise<boolean>} Whether all required files are cached
208
209
  *
209
210
  * @example
210
- * const status = await ModelRegistry.is_cached('onnx-community/bert-base-uncased-ONNX');
211
- * console.log(status.allCached); // true or false
211
+ * const cached = await ModelRegistry.is_cached('onnx-community/bert-base-uncased-ONNX');
212
+ * console.log(cached); // true or false
212
213
  */
213
214
  static async is_cached(modelId, options = {}) {
214
215
  return is_cached(modelId, options);
215
216
  }
216
217
 
217
218
  /**
218
- * Check if all files for a specific pipeline task are cached.
219
- * Automatically determines which components are needed based on the task.
219
+ * Checks if all files for a given model are already cached, with per-file detail.
220
+ * Automatically determines which files are needed using get_files().
220
221
  *
221
- * @param {string} task - The pipeline task (e.g., "text-generation", "background-removal")
222
222
  * @param {string} modelId - The model id
223
223
  * @param {Object} [options] - Optional parameters
224
224
  * @param {string} [options.cache_dir] - Custom cache directory
@@ -229,13 +229,60 @@ export class ModelRegistry {
229
229
  * @returns {Promise<import('./is_cached.js').CacheCheckResult>} Object with allCached boolean and files array with cache status
230
230
  *
231
231
  * @example
232
- * const status = await ModelRegistry.is_pipeline_cached('text-generation', 'onnx-community/gpt2-ONNX');
232
+ * const status = await ModelRegistry.is_cached_files('onnx-community/bert-base-uncased-ONNX');
233
233
  * console.log(status.allCached); // true or false
234
+ * console.log(status.files); // [{ file: 'config.json', cached: true }, ...]
235
+ */
236
+ static async is_cached_files(modelId, options = {}) {
237
+ return is_cached_files(modelId, options);
238
+ }
239
+
240
+ /**
241
+ * Quickly checks if all files for a specific pipeline task are cached by verifying
242
+ * `config.json` is present, then confirming all required files are cached.
243
+ * Returns a plain boolean — use `is_pipeline_cached_files` if you need per-file detail.
244
+ *
245
+ * @param {string} task - The pipeline task (e.g., "text-generation", "background-removal")
246
+ * @param {string} modelId - The model id
247
+ * @param {Object} [options] - Optional parameters
248
+ * @param {string} [options.cache_dir] - Custom cache directory
249
+ * @param {string} [options.revision] - Model revision (default: 'main')
250
+ * @param {import('../../configs.js').PretrainedConfig} [options.config] - Pre-loaded config
251
+ * @param {import('../dtypes.js').DataType|Record<string, import('../dtypes.js').DataType>} [options.dtype=null] - Override dtype
252
+ * @param {import('../devices.js').DeviceType|Record<string, import('../devices.js').DeviceType>} [options.device=null] - Override device
253
+ * @returns {Promise<boolean>} Whether all required files are cached
254
+ *
255
+ * @example
256
+ * const cached = await ModelRegistry.is_pipeline_cached('text-generation', 'onnx-community/gpt2-ONNX');
257
+ * console.log(cached); // true or false
234
258
  */
235
259
  static async is_pipeline_cached(task, modelId, options = {}) {
236
260
  return is_pipeline_cached(task, modelId, options);
237
261
  }
238
262
 
263
+ /**
264
+ * Checks if all files for a specific pipeline task are already cached, with per-file detail.
265
+ * Automatically determines which components are needed based on the task.
266
+ *
267
+ * @param {string} task - The pipeline task (e.g., "text-generation", "background-removal")
268
+ * @param {string} modelId - The model id
269
+ * @param {Object} [options] - Optional parameters
270
+ * @param {string} [options.cache_dir] - Custom cache directory
271
+ * @param {string} [options.revision] - Model revision (default: 'main')
272
+ * @param {import('../../configs.js').PretrainedConfig} [options.config] - Pre-loaded config
273
+ * @param {import('../dtypes.js').DataType|Record<string, import('../dtypes.js').DataType>} [options.dtype=null] - Override dtype
274
+ * @param {import('../devices.js').DeviceType|Record<string, import('../devices.js').DeviceType>} [options.device=null] - Override device
275
+ * @returns {Promise<import('./is_cached.js').CacheCheckResult>} Object with allCached boolean and files array with cache status
276
+ *
277
+ * @example
278
+ * const status = await ModelRegistry.is_pipeline_cached_files('text-generation', 'onnx-community/gpt2-ONNX');
279
+ * console.log(status.allCached); // true or false
280
+ * console.log(status.files); // [{ file: 'config.json', cached: true }, ...]
281
+ */
282
+ static async is_pipeline_cached_files(task, modelId, options = {}) {
283
+ return is_pipeline_cached_files(task, modelId, options);
284
+ }
285
+
239
286
  /**
240
287
  * Get metadata for a specific file without downloading it.
241
288
  *
@@ -7,6 +7,7 @@ import { getCache } from '../cache.js';
7
7
  import { buildResourcePaths, checkCachedResource, getFetchHeaders, getFile } from '../hub.js';
8
8
  import { isValidUrl } from '../hub/utils.js';
9
9
  import { logger } from '../logger.js';
10
+ import { memoizePromise } from '../memoize_promise.js';
10
11
 
11
12
  /**
12
13
  * @typedef {import('../hub.js').PretrainedOptions} PretrainedOptions
@@ -34,7 +35,7 @@ async function fetch_file_head(urlOrPath) {
34
35
 
35
36
  const headers = getFetchHeaders(urlOrPath);
36
37
  headers.set('Range', 'bytes=0-0');
37
- return env.fetch(urlOrPath, { method: 'GET', headers });
38
+ return env.fetch(urlOrPath, { method: 'GET', headers, cache: 'no-store' });
38
39
  }
39
40
 
40
41
  /**
@@ -49,7 +50,18 @@ async function fetch_file_head(urlOrPath) {
49
50
  * @param {PretrainedOptions} [options] An object containing optional parameters.
50
51
  * @returns {Promise<{exists: boolean, size?: number, contentType?: string, fromCache?: boolean}>} A Promise that resolves to file metadata.
51
52
  */
52
- export async function get_file_metadata(path_or_repo_id, filename, options = {}) {
53
+ export function get_file_metadata(path_or_repo_id, filename, options = {}) {
54
+ const key = JSON.stringify([
55
+ path_or_repo_id,
56
+ filename,
57
+ options?.revision,
58
+ options?.cache_dir,
59
+ options?.local_files_only,
60
+ ]);
61
+ return memoizePromise(key, () => _get_file_metadata(path_or_repo_id, filename, options));
62
+ }
63
+
64
+ async function _get_file_metadata(path_or_repo_id, filename, options) {
53
65
  /** @type {import('../cache.js').CacheInterface | null} */
54
66
  const cache = await getCache(options?.cache_dir);
55
67
  const { localPath, remoteURL, proposedCacheKey, validModelId } = buildResourcePaths(