// Copyright 2025 the V8 project authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.// Polyfills that Transformers.js / the ONNX runtime needs in JavaScript shells.class URL {href;constructor(url, base) {// DEBUG// console.log('URL', url, base);this.href = url;}}globalThis.URL = URL;// Polyfill fetch for shell-compatibility and to cache / preload model weights etc.let preload = { /* Initialized in init() below due to async. */ };async function redirectingFetch(url) {// DEBUG// console.log('fetch', url);if (url.startsWith("./"))url = JetStream.resources[url];// Redirect some paths to cached/preloaded resources.if (preload[url]) {return {ok: true,status: 200,arrayBuffer() { return preload[url]; },async blob() {return {size: preload[url].byteLength,async arrayBuffer() { return preload[url]; }}},};}throw new Error(`Unexpected resource requested in benchmark: ${url}`);};// JetStream benchmark harness. Reuse for two different Transformers.js tasks.// Assumes `preloadFiles(module)`, `initPipeline(pipelineFromTransformersJs)`,// and `doTask(initializedPipeline, inputArrayBuffer)` is in the global scope.class Benchmark {transformersJsModule;wasmBinary;pipeline;inputFile;output;async init() {this.transformersJsModule = await JetStream.dynamicImport(JetStream.preload.transformersJsModule);this.wasmBinary = await JetStream.getBinary(JetStream.preload.onnxWasmBinary);for (const url of Object.values(JetStream.preload)) {preload[url] = await JetStream.getBinary(url);}if ('inputFile' in JetStream.preload) {this.inputFile = (await JetStream.getBinary(JetStream.preload.inputFile)).buffer;// DEBUG// console.log('inputFile', this.inputFile.byteLength, 'bytes');}// After we have loaded everything close the door behind us to make sure no other network requests happen.globalThis.fetch = redirectingFetch;}async runIteration() {// Initialize the inference pipeline in the first iteration.if (!this.pipeline) {// TODO: Profile startup only: What is taking so much time here?let { env, pipeline } = this.transformersJsModule;env.allowRemoteModels = false;env.allowLocalModels = true;env.localModelPath = './transformersjs/build/models/';// Always select the Wasm backend, nothing else.delete env.backends.onnx.webgl;delete env.backends.onnx.webgpu;// Single-threaded only for now, since we cannot spawn workers in shells.// TODO: Implement sufficiently powerful workers in shells (or provide// polyfills).env.backends.onnx.wasm.numThreads = 1;// Do not specify path prefix, because this loads the JSEP build by default.// TODO: Do we want the JSEP build because it's the default online, or the// non-asyncified one, since it's the smaller / more performant one?// env.backends.onnx.wasm.wasmPaths = 'build/onnxruntime-web/';// So instead, give the ONNX runtime files directly:env.backends.onnx.wasm.wasmPaths = {// The ONNX runtime module is dynamically imported relative to the// Transformers.js module above, hence strip the prefix.// With preloading, this is an (absolute) blob URL, so the replace is a nop.mjs: JetStream.preload.onnxJsModule.replace('./transformersjs/build/', './')};// Give it the wasmBinary directly instead of a path, such that the// ONNX runtime uses asynchronous (not streaming) Wasm instantiation.// (To keep the shell and browser results comparable, and streaming// instantiation is not available in shells.)env.backends.onnx.wasm.wasmBinary = this.wasmBinary;this.pipeline = await initPipeline(pipeline);}this.output = await doTask(this.pipeline, this.inputFile);}validate() {validate(this.output);}}