tempest-react-sdk 0.72.0 → 0.73.0
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.
- package/dist/vision/core/graph.cjs.map +1 -1
- package/dist/vision/core/graph.js.map +1 -1
- package/dist/vision/core/metadata.cjs +2 -2
- package/dist/vision/core/metadata.cjs.map +1 -1
- package/dist/vision/core/metadata.js +101 -29
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/core/session.cjs +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js +59 -48
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/index.cjs +1 -1
- package/dist/vision/index.cjs.map +1 -1
- package/dist/vision/index.js +1 -1
- package/dist/vision/index.js.map +1 -1
- package/dist/vision.d.ts +25 -21
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.cjs","names":[],"sources":["../../../src/vision/core/session.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Thin wrapper around `onnxruntime-web` `InferenceSession` with typed metadata.\n */\n\nimport type * as ort from \"onnxruntime-web\";\nimport * as ortRuntime from \"onnxruntime-web\";\n\nimport { DEFAULT_TENSOR_TYPE, hasFloat16Array, tensorTypeFor, toFeedData } from \"./dtypes\";\nimport { InferenceError, ModelLoadError } from \"./exceptions\";\nimport { type DeclaredShape, declaredShapesFrom } from \"./graph\";\nimport { readModelInputTypes, readModelMetadata } from \"./metadata\";\nimport {\n FALLBACK_PROVIDER,\n type ProviderSpec,\n detectProviders,\n providerName,\n resolveProviders,\n} from \"./providers\";\n\n/** Anything `InferenceSession.create` accepts. */\nexport type ModelSource = string | ArrayBufferLike | Uint8Array;\n\n/**\n * Metadata key naming the level a model was graph-optimized at offline.\n *\n * Written by the Python SDK's `optimize_model`; both test suites pin the same\n * string, so a rename on one side fails. See {@link OrtSession.create} for what\n * the session does when it finds it.\n */\nexport const GRAPH_OPTIMIZATION_KEY = \"ort_vision_sdk.graph_optimization\";\n\n/**\n * An 84-byte ONNX model — one `Identity` on a float `[1]` — used to start the runtime.\n *\n * Generated with `onnx.helper` (opset 13, IR 7, producer `ort-vision-sdk`).\n * See {@link warmRuntime} for why it exists.\n */\nconst RUNTIME_PROBE_MODEL =\n \"CAcSDm9ydC12aXNpb24tc2RrOjoKEAoBeBIBeSIISWRlbnRpdHkSBHdhcm1aDwoBeBIKCggIARIECgIIAWIPCgF5EgoKCAgBEgQKAggBQgQKABAN\";\n\n/** Runtime start-ups already begun on this page, keyed by provider names. */\nconst runtimeWarmups = new Map<string, Promise<void>>();\n\n/**\n * Start ONNX Runtime's backends for a provider list, once per page.\n *\n * ORT downloads and compiles its WebAssembly binary — 12.8 MB for the plain\n * WASM build, 25.9 MB for the one carrying WebGPU — inside the first\n * `InferenceSession.create`. {@link OrtSession.create} only reaches that call\n * after it has downloaded the model, so on a real network the two largest\n * downloads of a page load ran one after the other. Creating and releasing a\n * session on a tiny model while the real one downloads lets them overlap; the\n * real `create` then finds the runtime ready.\n *\n * A failure here is swallowed: the real `create` runs against the same runtime\n * and reports the same problem with the right model in the message.\n *\n * @param specs Providers the real session will use.\n * @returns Settles when the runtime is up, or when starting it failed.\n */\nfunction warmRuntime(specs: readonly ProviderSpec[]): Promise<void> {\n const key = specs.map(providerName).join(\",\");\n let pending = runtimeWarmups.get(key);\n if (pending === undefined) {\n pending = (async () => {\n try {\n const probe = Uint8Array.from(atob(RUNTIME_PROBE_MODEL), (c) => c.charCodeAt(0));\n const session = await ortRuntime.InferenceSession.create(probe, {\n executionProviders:\n specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n });\n await session.release();\n } catch {\n return;\n }\n })();\n runtimeWarmups.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Warn that a model optimized offline is about to run on WebGPU.\n *\n * `optimize_model` fuses operators for the CPU, which is what the WASM backend\n * runs. On WebGPU some of those fused nodes have no GPU kernel: on a\n * YOLO11n-seg, ONNX Runtime placed 2 nodes on the CPU for the optimized file\n * and none for the original, so every inference pays GPU↔CPU copies. The SDK\n * cannot swap the file, so it says which one to ship.\n */\nfunction warnPreOptimizedOnWebGpu(): void {\n console.warn(\n \"[@ort-vision-sdk/web] This model was pre-optimized by optimize_model, which targets the \" +\n \"WASM backend; on WebGPU some of its fused nodes fall back to the CPU. For WebGPU, ship \" +\n \"the original export instead.\",\n );\n}\n\n/**\n * Metadata key the Python SDK's `quantize_model` writes on an INT8 model.\n *\n * Mirrored by `QUANTIZATION_KEY` in the Python SDK; both test suites pin the\n * string. See {@link keepQuantizedOffWebGpu} for what a session does with it.\n */\nexport const QUANTIZATION_KEY = \"ort_vision_sdk.quantization\";\n\n/**\n * Drop `webgpu` from the providers of a model `quantize_model` produced.\n *\n * ONNX Runtime Web's WebGPU `DequantizeLinear` rejects the quantized bias such\n * a model carries — `scale and zero-point inputs must have the same rank` —\n * so the first `predict()` fails; and a variant with the bias left in float\n * ran but returned different detections than WASM for the same file. The\n * model is fine on WASM, which is also where INT8 pays (52.7 ms vs 68.4 ms on\n * a YOLO11n-seg), so the session runs there and says so.\n *\n * @param specs Providers that survived detection.\n * @param metadata The model's metadata map.\n * @returns `specs` without `webgpu` when the model is marked quantized; the\n * WASM fallback when nothing else is left.\n */\nfunction keepQuantizedOffWebGpu(\n specs: readonly ProviderSpec[],\n metadata: Readonly<Record<string, string>>,\n): ProviderSpec[] {\n if (metadata[QUANTIZATION_KEY] === undefined) return [...specs];\n const kept = specs.filter((spec) => providerName(spec) !== \"webgpu\");\n if (kept.length === specs.length) return kept;\n console.warn(\n `[@ort-vision-sdk/web] This model was quantized by quantize_model (${metadata[QUANTIZATION_KEY]}); ` +\n \"ONNX Runtime Web's WebGPU backend cannot run its quantized operators, so it runs on WASM.\",\n );\n return kept.length > 0 ? kept : [FALLBACK_PROVIDER];\n}\n\n/** Cache Storage bucket used when {@link OrtSessionOptions.cache} is `true`. */\nexport const DEFAULT_MODEL_CACHE = \"ort-vision-sdk-models\";\n\n/**\n * Fetch a model URL as bytes so its metadata can be read.\n *\n * Falls back to the URL itself when the fetch fails, letting ORT try its own\n * load path: losing the metadata map is a downgrade, but failing to load a model\n * that ORT could have fetched would be a regression.\n *\n * @param url Where the `.onnx` lives.\n * @param cacheName Cache Storage bucket to read from and fill, or `null` to\n * always go to the network.\n * @returns The model bytes, or the original URL when they could not be fetched.\n */\nasync function fetchModel(url: string, cacheName: string | null): Promise<Uint8Array | string> {\n const cache = cacheName === null ? null : await openCache(cacheName);\n if (cache !== null) {\n const hit = await cache.match(url).catch(() => undefined);\n if (hit !== undefined) return new Uint8Array(await hit.arrayBuffer());\n }\n try {\n const response = await fetch(url);\n if (!response.ok) {\n warnMetadataUnavailable(url, `HTTP ${response.status} ${response.statusText}`);\n return url;\n }\n const buffer = await response.arrayBuffer();\n if (cache !== null) await storeModel(cache, url, buffer);\n return new Uint8Array(buffer);\n } catch (err) {\n warnMetadataUnavailable(url, (err as Error).message);\n return url;\n }\n}\n\n/**\n * Put a model's bytes into the cache, never failing the load over it.\n *\n * Stores a fresh `Response` built from bytes already read rather than a\n * `clone()` of the network response: one read, and nothing that can throw\n * synchronously outside the guard. Awaited on purpose — a `put` left running\n * would keep its copy of the model reachable while ORT builds the session, the\n * same doubled peak {@link OrtSession.create} orders its reads to avoid.\n *\n * @param cache The open bucket.\n * @param url Cache key.\n * @param buffer The model.\n */\nasync function storeModel(cache: Cache, url: string, buffer: ArrayBuffer): Promise<void> {\n try {\n await cache.put(url, new Response(buffer));\n } catch {\n return;\n }\n}\n\n/**\n * Open a Cache Storage bucket, or report that there is none to open.\n *\n * Cache Storage only exists in secure contexts (HTTPS, `localhost`), and a\n * browser may refuse it outright — private windows, blocked site data, an\n * exhausted quota. None of that is worth failing a model load over: the model\n * is fetched from the network as if caching had not been asked for. A failed\n * `put` is swallowed for the same reason — see {@link storeModel}.\n *\n * @param name Bucket name.\n * @returns The cache, or `null` when this environment cannot provide one.\n */\nasync function openCache(name: string): Promise<Cache | null> {\n if (typeof caches === \"undefined\") return null;\n try {\n return await caches.open(name);\n } catch {\n return null;\n }\n}\n\n/**\n * Warn that a model's metadata could not be read, and say what that costs.\n *\n * The fallback itself is right — losing the metadata beats failing a load that\n * ORT could have completed on its own — but it used to be silent, and the\n * symptom it produces is remote from the cause: class names come back as\n * `class_0`, `class_1`, ... with nothing anywhere explaining why. Whoever hits\n * this needs to be told that passing `labels` is the way out.\n *\n * @param url The model URL that could not be fetched here.\n * @param reason What went wrong, as reported by `fetch`.\n */\nfunction warnMetadataUnavailable(url: string, reason: string): void {\n console.warn(\n `[@ort-vision-sdk/web] Could not fetch ${url} to read its metadata (${reason}). ` +\n \"Letting ONNX Runtime load it instead: the model will work, but its baked-in \" +\n \"class names are unavailable, so labels fall back to class_0, class_1, ... \" +\n \"Pass `labels` explicitly to name them.\",\n );\n}\n\nexport interface OrtSessionOptions {\n /**\n * Execution providers in preference order. `undefined` uses {@link DEFAULT_PROVIDERS}.\n *\n * Each entry is a name (`\"webgpu\"`, `\"wasm\"`) or ORT's config object for that\n * provider, which passes provider options through untouched —\n * `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`.\n *\n * Naming one explicitly also opts into a `console.warn` when this browser\n * cannot offer it, instead of falling back in silence.\n */\n readonly providers?: readonly ProviderSpec[];\n /**\n * Keep a URL model in the browser's Cache Storage between page loads.\n *\n * `true` uses the {@link DEFAULT_MODEL_CACHE} bucket; a string names the\n * bucket. A later `create` with the same URL reads the bytes from the cache\n * instead of the network — for a model of several megabytes, the bulk of\n * what a returning visitor waits for. Defaults to `false`.\n *\n * The URL is the cache key and nothing expires it: publish a changed model\n * under a new URL (`yolo.v2.onnx`, `?v=2`) or a new bucket name, or delete\n * the bucket with `caches.delete(name)`. Ignored for models passed as bytes,\n * and silently skipped where Cache Storage is unavailable (non-secure\n * contexts, blocked site data).\n */\n readonly cache?: boolean | string;\n /** Optional ORT session options forwarded to `InferenceSession.create`. */\n readonly sessionOptions?: ort.InferenceSession.SessionOptions;\n /**\n * Whether to read the model's custom metadata map (`names`, `task`, `imgsz`).\n * Defaults to `true`.\n *\n * The runtime does not expose that map, so it is read from the file itself —\n * which means a URL model is fetched here and handed to ORT as bytes instead\n * of letting ORT fetch it. That is the same single download either way, and\n * it is what lets a task resolve its labels off the model. Set to `false` to\n * keep the URL path untouched (unless {@link cache} is set, which needs the\n * bytes) and leave {@link OrtSession.metadata} empty.\n *\n * `false` is also the escape hatch when a device cannot afford the bytes: the\n * fetched buffer is dropped before ORT builds the graph (see\n * {@link OrtSession.create}), but ORT's own load path still keeps the model out\n * of reach of anything the SDK holds. A session built this way resolves its\n * input size from the graph as usual — only the class names are lost, so a\n * caller taking this route has to pass `labels` itself.\n */\n readonly readMetadata?: boolean;\n}\n\n/**\n * Warn when a provider named explicitly by the caller is not going to run.\n *\n * Only explicit requests are worth a warning. The default list exists precisely\n * so that falling from `webgpu` to `wasm` is the expected outcome — but a caller\n * who wrote `providers: [\"webgpu\"]` and lands on WASM has a page several times\n * slower than intended and nothing in the console to explain it.\n *\n * @param requested Providers that were asked for.\n * @param effective Providers that survived capability detection.\n */\nfunction warnOnDroppedProviders(requested: readonly string[], effective: readonly string[]): void {\n const dropped = requested.filter((provider) => !effective.includes(provider));\n if (dropped.length === 0) {\n return;\n }\n console.warn(\n `This browser cannot offer the requested execution provider(s) ${JSON.stringify(dropped)}; ` +\n `the session will run on ${JSON.stringify(effective)}. Inference still produces correct ` +\n \"results, on the fallback provider.\",\n );\n}\n\n/**\n * Name the tensor type of every graph input, straight from the model bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → tensor type name. Empty when the file carries no\n * readable graph, which callers read as \"assume float32\".\n */\nfunction declaredInputTypes(model: Uint8Array | ArrayBufferLike): Readonly<Record<string, string>> {\n const declared = readModelInputTypes(model);\n const named: Record<string, string> = {};\n for (const [name, elemType] of Object.entries(declared)) {\n named[name] = tensorTypeFor(elemType);\n }\n return named;\n}\n\n/**\n * Warn when the model's bytes were in hand but no input type came back.\n *\n * Every ONNX graph declares at least one input, so an empty result from bytes\n * means the reader failed, not that the model said nothing. Without this the\n * failure is invisible: the session falls back to float32, which is right for\n * most models and wrong for exactly the half-precision ones this reader exists\n * to support — so it looks like nothing is broken until a `predict()` throws\n * `Unexpected input data type`. That is how a 1 MB ceiling on the graph\n * descent shipped in 0.9.0 and reached a consumer.\n */\nfunction warnOnUnreadableTypes(): void {\n console.warn(\n \"Could not read any input type from this model's bytes; feeds will be built as float32. \" +\n \"A half-precision model will fail at inference with 'Unexpected input data type'. \" +\n \"Please report this with the model that produced it.\",\n );\n}\n\n/**\n * Refuse a half-precision model in an environment that cannot feed one.\n *\n * ORT requires a real `Float16Array` for a `float16` tensor — the same bits in\n * a `Uint16Array` are rejected — and not every browser has one yet. Without\n * this check the session builds happily and the first `predict()` throws from\n * inside the preprocessing, which is both later and further from the cause.\n *\n * @param inputTypes Tensor type per input name.\n * @throws {@link ModelLoadError} when the graph wants half precision and the\n * runtime has no `Float16Array`.\n */\nfunction assertFeedableTypes(inputTypes: Readonly<Record<string, string>>): void {\n const half = Object.entries(inputTypes).filter(([, type]) => type === \"float16\");\n if (half.length === 0 || hasFloat16Array()) return;\n const names = half.map(([name]) => name).join(\", \");\n throw new ModelLoadError(\n `This model declares half-precision input(s) [${names}], but this environment has no ` +\n \"Float16Array, which ONNX Runtime requires for a float16 tensor. Use a float32 export \" +\n \"of the model, or run in a browser that supports Float16Array.\",\n );\n}\n\n/**\n * Wrap an ONNX Runtime Web `InferenceSession` with convenient metadata access.\n *\n * The wrapper exposes input/output names and the shapes the graph declares,\n * manages execution-provider selection, provides a typed {@link OrtSession.run}\n * method, and releases the native session through {@link OrtSession.release}.\n */\nexport class OrtSession {\n private constructor(\n private readonly _session: ort.InferenceSession,\n /**\n * Execution providers this session is expected to run on.\n *\n * The requested list narrowed to what this browser can actually offer — a\n * `webgpu` entry survives only where an adapter exists. Best-effort: ORT-Web\n * exposes no way to ask which provider a session ended up on, so an entry\n * here means \"not ruled out\", not \"confirmed\". See\n * {@link requestedProviders} for what was asked for.\n *\n * When nothing survives — a caller asking for `webgpu` alone on a device\n * without it — this falls back to {@link FALLBACK_PROVIDER}, which ORT-Web\n * can always run. Handing ORT the unsatisfiable list instead makes\n * `InferenceSession.create` reject with \"no available backend found\", so the\n * page gets no inference at all rather than the slow-but-working fallback\n * the `console.warn` describes. Measured in a real Chromium, where\n * `navigator.gpu` exists but yields no adapter.\n */\n public readonly providers: readonly string[],\n private readonly _metadata: Readonly<Record<string, string>>,\n /**\n * Execution providers that were asked for, after defaults were applied.\n *\n * Kept separate because ORT-Web falls back silently: a page that asks for\n * `webgpu` on a device without it runs on WASM and is told nothing.\n */\n public readonly requestedProviders: readonly string[],\n /**\n * Tensor type each input declares, keyed by input name.\n *\n * Read from the model file, not from the session: `inputMetadata` is\n * `undefined` on `onnxruntime-web` 1.20.1. Empty when the bytes were never\n * in hand — a URL loaded with `readMetadata: false` — in which case every\n * feed is built as float32, the behaviour before this existed.\n */\n private readonly _inputTypes: Readonly<Record<string, string>> = {},\n ) {}\n\n /**\n * Tail of the run queue: settles when the latest queued run has finished.\n *\n * See {@link run} for why runs are serialized.\n */\n private _runQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Load an ONNX model into an ORT inference session.\n *\n * The metadata map is read **before** the session is built, and that order is\n * load-bearing on memory-constrained devices. ORT copies the model into its\n * WASM heap and then allocates the graph and the weights on top of that copy;\n * a `readModelMetadata` call placed after `InferenceSession.create` keeps the\n * JavaScript-side buffer reachable across the whole build, so a 5 MB model\n * costs 5 MB of JS heap plus 5 MB of WASM heap plus the weights at the same\n * instant. Reading first makes the buffer collectable as soon as ORT has copied\n * it — on a phone that was the difference between a session and\n * `Can't create a session. failed to allocate a buffer of size N`.\n *\n * The provider probe and the model download run concurrently: neither\n * depends on the other, and on a real GPU `requestAdapter()` is not free.\n * When the model is downloaded here, ORT's runtime is started alongside the\n * download too — see {@link warmRuntime}.\n *\n * A model whose metadata carries {@link GRAPH_OPTIMIZATION_KEY} was already\n * optimized offline by the Python SDK's `optimize_model`, so it is loaded\n * with `graphOptimizationLevel: \"disabled\"` instead of paying the optimizer a\n * second time — measured on a YOLO11n-seg under WASM, 29 ms of session\n * creation down to 12 ms with unchanged inference time. An explicit\n * `graphOptimizationLevel` in `sessionOptions` always wins. The mark is read\n * with the rest of the metadata, so `readMetadata: false` skips it too.\n *\n * @param model Either a URL string, or a `Uint8Array`/`ArrayBuffer` containing the model bytes.\n * @param options Provider list, pass-through `SessionOptions`, and whether to\n * read the model's metadata map (see {@link OrtSessionOptions.readMetadata}).\n * @throws {@link ModelLoadError} if the model cannot be loaded.\n */\n static async create(model: ModelSource, options: OrtSessionOptions = {}): Promise<OrtSession> {\n const requested = resolveProviders(options.providers);\n const wantsMetadata = options.readMetadata !== false;\n const cacheName =\n options.cache === true ? DEFAULT_MODEL_CACHE : options.cache ? options.cache : null;\n const shouldFetch = typeof model === \"string\" && (wantsMetadata || cacheName !== null);\n const detection = detectProviders(requested).then((detected) =>\n detected.length > 0 ? detected : [FALLBACK_PROVIDER],\n );\n const [detected, source] = await Promise.all([\n detection,\n shouldFetch ? fetchModel(model, cacheName) : Promise.resolve(model),\n shouldFetch ? detection.then(warmRuntime) : Promise.resolve(),\n ]);\n const metadata =\n wantsMetadata && typeof source !== \"string\" ? readModelMetadata(source) : {};\n const specs = keepQuantizedOffWebGpu(detected, metadata);\n const requestedNames = requested.map(providerName);\n const providers = specs.map(providerName);\n if (options.providers !== undefined && options.providers.length > 0) {\n warnOnDroppedProviders(requestedNames, detected.map(providerName));\n }\n if (metadata[GRAPH_OPTIMIZATION_KEY] !== undefined && providers.includes(\"webgpu\")) {\n warnPreOptimizedOnWebGpu();\n }\n const preOptimized =\n metadata[GRAPH_OPTIMIZATION_KEY] !== undefined &&\n options.sessionOptions?.graphOptimizationLevel === undefined;\n const sessionOptions: ort.InferenceSession.SessionOptions = {\n ...(preOptimized ? { graphOptimizationLevel: \"disabled\" as const } : {}),\n ...(options.sessionOptions ?? {}),\n executionProviders: specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n };\n const inputTypes = typeof source !== \"string\" ? declaredInputTypes(source) : {};\n if (typeof source !== \"string\" && Object.keys(inputTypes).length === 0) {\n warnOnUnreadableTypes();\n }\n assertFeedableTypes(inputTypes);\n\n let session: ort.InferenceSession;\n try {\n if (typeof source === \"string\") {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else if (source instanceof Uint8Array) {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else {\n session = await ortRuntime.InferenceSession.create(\n source as ArrayBuffer,\n sessionOptions,\n );\n }\n } catch (err) {\n throw new ModelLoadError(`Failed to load ONNX model: ${(err as Error).message}`, {\n cause: err,\n });\n }\n\n return new OrtSession(session, providers, metadata, requestedNames, inputTypes);\n }\n\n /**\n * Tensor type each input declares, in declaration order.\n *\n * `\"float32\"` for a normal export, `\"float16\"` for one exported with\n * `half=True`. ORT matches a feed's type against this exactly, so the tasks\n * read it and convert at the feed boundary.\n */\n get inputDtypes(): readonly string[] {\n return this.inputNames.map((name) => this._inputTypes[name] ?? DEFAULT_TENSOR_TYPE);\n }\n\n /** Tensor type the first input declares. */\n get inputDtype(): string {\n return this._inputTypes[this.inputName] ?? DEFAULT_TENSOR_TYPE;\n }\n\n /** Names of the model's inputs, in declaration order. */\n get inputNames(): readonly string[] {\n return this._session.inputNames;\n }\n\n /** Name of the first (and usually only) input. */\n get inputName(): string {\n const name = this._session.inputNames[0];\n if (name === undefined) {\n throw new InferenceError(\"Model has no inputs.\");\n }\n return name;\n }\n\n /** Names of the model's outputs, in declaration order. */\n get outputNames(): readonly string[] {\n return this._session.outputNames;\n }\n\n /**\n * Shapes the graph declares for its inputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Empty shapes mean the runtime\n * reported no metadata — either a non-tensor input, or an `onnxruntime-web`\n * older than 1.21, which predates input metadata.\n */\n get inputShapes(): readonly DeclaredShape[] {\n return declaredShapesFrom(\n this._session.inputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n );\n }\n\n /**\n * Shape the graph declares for its first input, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get inputShape(): DeclaredShape {\n return this.inputShapes[0] ?? [];\n }\n\n /**\n * Shapes the graph declares for its outputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Reading them is how a task can\n * tell how many classes a head emits without being told.\n */\n get outputShapes(): readonly DeclaredShape[] {\n return declaredShapesFrom(\n this._session.outputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n );\n }\n\n /**\n * Shape the graph declares for its first output, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get outputShape(): DeclaredShape {\n return this.outputShapes[0] ?? [];\n }\n\n /**\n * The model's custom metadata map — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export.\n *\n * Read from the model's bytes at load time, since the runtime does not expose\n * it. Empty when the session was created with `readMetadata: false`, from a\n * URL that could not be fetched here, or from a model carrying no metadata.\n */\n get metadata(): Readonly<Record<string, string>> {\n return this._metadata;\n }\n\n /**\n * Release the native session and free its memory.\n *\n * Call it when a session is discarded while the page lives on — rebuilding a\n * task at a different input size, swapping in a newer model. A failure from\n * the runtime is ignored: a session being torn down has nothing left to fail\n * at, and the caller is already moving on.\n */\n async release(): Promise<void> {\n await this._session.release().catch(() => undefined);\n }\n\n /** The underlying `onnxruntime-web` session, for advanced use cases. */\n get raw(): ort.InferenceSession {\n return this._session;\n }\n\n /**\n * Run inference and return all outputs.\n *\n * Runs on one session are serialized. ONNX Runtime Web refuses a second\n * `run` while one is in flight — it rejects with `Session already started` —\n * so two overlapping `predict()` calls on the same task used to fail. Queued\n * here, they overlap where they can: while one run executes (in a worker,\n * with `env.wasm.proxy`, or on the GPU), the next `predict()` decodes and\n * preprocesses its frame and only waits for its turn at the runtime. A run\n * that fails does not block the ones behind it.\n *\n * @param feeds Map of input name to `ort.Tensor`. Keys must match {@link inputNames}.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n run(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n const turn = this._runQueue.then(() => this._runNow(feeds));\n this._runQueue = turn.catch(() => undefined);\n return turn;\n }\n\n /**\n * Execute one run immediately; only {@link run}'s queue calls this.\n *\n * @param feeds Map of input name to `ort.Tensor`.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n private async _runNow(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n try {\n const result = await this._session.run(this._asDeclaredTypes(feeds));\n return result as Record<string, ort.Tensor>;\n } catch (err) {\n throw new InferenceError(`Inference failed: ${(err as Error).message}`, { cause: err });\n }\n }\n\n /**\n * Rebuild any feed whose type does not match what its input declares.\n *\n * ORT matches feed types against the graph exactly: a float32 tensor against\n * a `half=True` export fails the run with `Unexpected input data type`. Every\n * preprocessing path in this SDK produces `Float32Array`, on purpose — the\n * normalization arithmetic belongs in single precision — so the conversion\n * happens here, once, at the only boundary all of them pass through. A feed\n * that already carries the declared type is handed on untouched, so a caller\n * building its own half tensor pays nothing.\n *\n * @param feeds The tensors to run with.\n * @returns The same mapping, with mismatched float32 feeds converted.\n */\n private _asDeclaredTypes(feeds: Record<string, ort.Tensor>): Record<string, ort.Tensor> {\n let converted: Record<string, ort.Tensor> | null = null;\n for (const [name, tensor] of Object.entries(feeds)) {\n const declared = this._inputTypes[name];\n if (declared === undefined || declared === tensor.type) continue;\n if (!(tensor.data instanceof Float32Array)) continue;\n const data = toFeedData(tensor.data, declared);\n if (data === tensor.data) continue;\n converted ??= { ...feeds };\n converted[name] = new ortRuntime.Tensor(\n declared as \"float16\",\n data as unknown as Float32Array,\n tensor.dims as number[],\n );\n }\n return converted ?? feeds;\n }\n}\n"],"mappings":"oPA8BA,IAAa,EAAyB,oCAQhC,EACF,mHAGE,EAAiB,IAAI,IAmB3B,SAAS,EAAY,EAA+C,CAChE,IAAM,EAAM,EAAM,IAAI,EAAA,YAAY,CAAC,CAAC,KAAK,GAAG,EACxC,EAAU,EAAe,IAAI,CAAG,EAgBpC,OAfI,IAAY,IAAA,KACZ,GAAW,SAAY,CACnB,GAAI,CACA,IAAM,EAAQ,WAAW,KAAK,KAAK,CAAmB,EAAI,GAAM,EAAE,WAAW,CAAC,CAAC,EAK/E,MAAM,MAJgB,EAAW,iBAAiB,OAAO,EAAO,CAC5D,mBACI,CACR,CAAC,EAAA,CACa,QAAQ,CAC1B,MAAQ,CACJ,MACJ,CACJ,EAAA,CAAG,EACH,EAAe,IAAI,EAAK,CAAO,GAE5B,CACX,CAWA,SAAS,GAAiC,CACtC,QAAQ,KACJ,6MAGJ,CACJ,CAQA,IAAa,EAAmB,8BAiBhC,SAAS,EACL,EACA,EACc,CACd,GAAI,EAAA,iCAA+B,IAAA,GAAW,MAAO,CAAC,GAAG,CAAK,EAC9D,IAAM,EAAO,EAAM,OAAQ,GAAS,EAAA,aAAa,CAAI,IAAM,QAAQ,EAMnE,OALI,EAAK,SAAW,EAAM,OAAe,GACzC,QAAQ,KACJ,qEAAqE,EAAS,GAAkB,6FAEpG,EACO,EAAK,OAAS,EAAI,EAAO,CAAC,EAAA,iBAAiB,EACtD,CAGA,IAAa,EAAsB,wBAcnC,eAAe,EAAW,EAAa,EAAwD,CAC3F,IAAM,EAAQ,IAAc,KAAO,KAAO,MAAM,EAAU,CAAS,EACnE,GAAI,IAAU,KAAM,CAChB,IAAM,EAAM,MAAM,EAAM,MAAM,CAAG,CAAC,CAAC,UAAY,IAAA,EAAS,EACxD,GAAI,IAAQ,IAAA,GAAW,OAAO,IAAI,WAAW,MAAM,EAAI,YAAY,CAAC,CACxE,CACA,GAAI,CACA,IAAM,EAAW,MAAM,MAAM,CAAG,EAChC,GAAI,CAAC,EAAS,GAEV,OADA,EAAwB,EAAK,QAAQ,EAAS,OAAO,GAAG,EAAS,YAAY,EACtE,EAEX,IAAM,EAAS,MAAM,EAAS,YAAY,EAE1C,OADI,IAAU,MAAM,MAAM,EAAW,EAAO,EAAK,CAAM,EAChD,IAAI,WAAW,CAAM,CAChC,OAAS,EAAK,CAEV,OADA,EAAwB,EAAM,EAAc,OAAO,EAC5C,CACX,CACJ,CAeA,eAAe,EAAW,EAAc,EAAa,EAAoC,CACrF,GAAI,CACA,MAAM,EAAM,IAAI,EAAK,IAAI,SAAS,CAAM,CAAC,CAC7C,MAAQ,CACJ,MACJ,CACJ,CAcA,eAAe,EAAU,EAAqC,CAC1D,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,GAAI,CACA,OAAO,MAAM,OAAO,KAAK,CAAI,CACjC,MAAQ,CACJ,OAAO,IACX,CACJ,CAcA,SAAS,EAAwB,EAAa,EAAsB,CAChE,QAAQ,KACJ,yCAAyC,EAAI,yBAAyB,EAAO,kMAIjF,CACJ,CA+DA,SAAS,EAAuB,EAA8B,EAAoC,CAC9F,IAAM,EAAU,EAAU,OAAQ,GAAa,CAAC,EAAU,SAAS,CAAQ,CAAC,EACxE,EAAQ,SAAW,GAGvB,QAAQ,KACJ,iEAAiE,KAAK,UAAU,CAAO,EAAE,4BAC1D,KAAK,UAAU,CAAS,EAAE,sEAE7D,CACJ,CASA,SAAS,EAAmB,EAAuE,CAC/F,IAAM,EAAW,EAAA,oBAAoB,CAAK,EACpC,EAAgC,CAAC,EACvC,IAAK,GAAM,CAAC,EAAM,KAAa,OAAO,QAAQ,CAAQ,EAClD,EAAM,GAAQ,EAAA,cAAc,CAAQ,EAExC,OAAO,CACX,CAaA,SAAS,GAA8B,CACnC,QAAQ,KACJ,6NAGJ,CACJ,CAcA,SAAS,EAAoB,EAAoD,CAC7E,IAAM,EAAO,OAAO,QAAQ,CAAU,CAAC,CAAC,QAAQ,EAAG,KAAU,IAAS,SAAS,EAC/E,GAAI,EAAK,SAAW,GAAK,EAAA,gBAAgB,EAAG,OAC5C,IAAM,EAAQ,EAAK,KAAK,CAAC,KAAU,CAAI,CAAC,CAAC,KAAK,IAAI,EAClD,MAAM,IAAI,EAAA,eACN,gDAAgD,EAAM,kLAG1D,CACJ,CASA,IAAa,EAAb,MAAa,CAAW,CAEC,SAkBD,UACC,UAOD,mBASC,YApCrB,YACI,EAkBA,EACA,EAOA,EASA,EAAiE,CAAC,EACpE,CApCmB,KAAA,SAAA,EAkBD,KAAA,UAAA,EACC,KAAA,UAAA,EAOD,KAAA,mBAAA,EASC,KAAA,YAAA,CAClB,CAOH,UAAsC,QAAQ,QAAQ,EAiCtD,aAAa,OAAO,EAAoB,EAA6B,CAAC,EAAwB,CAC1F,IAAM,EAAY,EAAA,iBAAiB,EAAQ,SAAS,EAC9C,EAAgB,EAAQ,eAAiB,GACzC,EACF,EAAQ,QAAU,GAAO,EAAsB,EAAQ,MAAQ,EAAQ,MAAQ,KAC7E,EAAc,OAAO,GAAU,WAAa,GAAiB,IAAc,MAC3E,EAAY,EAAA,gBAAgB,CAAS,CAAC,CAAC,KAAM,GAC/C,EAAS,OAAS,EAAI,EAAW,CAAC,EAAA,iBAAiB,CACvD,EACM,CAAC,EAAU,GAAU,MAAM,QAAQ,IAAI,CACzC,EACA,EAAc,EAAW,EAAO,CAAS,EAAI,QAAQ,QAAQ,CAAK,EAClE,EAAc,EAAU,KAAK,CAAW,EAAI,QAAQ,QAAQ,CAChE,CAAC,EACK,EACF,GAAiB,OAAO,GAAW,SAAW,EAAA,kBAAkB,CAAM,EAAI,CAAC,EACzE,EAAQ,EAAuB,EAAU,CAAQ,EACjD,EAAiB,EAAU,IAAI,EAAA,YAAY,EAC3C,EAAY,EAAM,IAAI,EAAA,YAAY,EACpC,EAAQ,YAAc,IAAA,IAAa,EAAQ,UAAU,OAAS,GAC9D,EAAuB,EAAgB,EAAS,IAAI,EAAA,YAAY,CAAC,EAEjE,EAAA,uCAAqC,IAAA,IAAa,EAAU,SAAS,QAAQ,GAC7E,EAAyB,EAK7B,IAAM,EAAsD,CACxD,GAHA,EAAA,uCAAqC,IAAA,IACrC,EAAQ,gBAAgB,yBAA2B,IAAA,GAEhC,CAAE,uBAAwB,UAAoB,EAAI,CAAC,EACtE,GAAI,EAAQ,gBAAkB,CAAC,EAC/B,mBAAoB,CACxB,EACM,EAAa,OAAO,GAAW,SAAwC,CAAC,EAA9B,EAAmB,CAAM,EACrE,OAAO,GAAW,UAAY,OAAO,KAAK,CAAU,CAAC,CAAC,SAAW,GACjE,EAAsB,EAE1B,EAAoB,CAAU,EAE9B,IAAI,EACJ,GAAI,CACA,AAKI,GALA,OAAO,GAAW,UAEX,aAAkB,WADf,MAAM,EAAW,iBAAiB,OAAO,EAAQ,CAAc,EASjF,OAAS,EAAK,CACV,MAAM,IAAI,EAAA,eAAe,8BAA+B,EAAc,UAAW,CAC7E,MAAO,CACX,CAAC,CACL,CAEA,OAAO,IAAI,EAAW,EAAS,EAAW,EAAU,EAAgB,CAAU,CAClF,CASA,IAAI,aAAiC,CACjC,OAAO,KAAK,WAAW,IAAK,GAAS,KAAK,YAAY,IAAA,SAA4B,CACtF,CAGA,IAAI,YAAqB,CACrB,OAAO,KAAK,YAAY,KAAK,YAAA,SACjC,CAGA,IAAI,YAAgC,CAChC,OAAO,KAAK,SAAS,UACzB,CAGA,IAAI,WAAoB,CACpB,IAAM,EAAO,KAAK,SAAS,WAAW,GACtC,GAAI,IAAS,IAAA,GACT,MAAM,IAAI,EAAA,eAAe,sBAAsB,EAEnD,OAAO,CACX,CAGA,IAAI,aAAiC,CACjC,OAAO,KAAK,SAAS,WACzB,CASA,IAAI,aAAwC,CACxC,OAAO,EAAA,mBACH,KAAK,SAAS,aAElB,CACJ,CAOA,IAAI,YAA4B,CAC5B,OAAO,KAAK,YAAY,IAAM,CAAC,CACnC,CAQA,IAAI,cAAyC,CACzC,OAAO,EAAA,mBACH,KAAK,SAAS,cAElB,CACJ,CAOA,IAAI,aAA6B,CAC7B,OAAO,KAAK,aAAa,IAAM,CAAC,CACpC,CAUA,IAAI,UAA6C,CAC7C,OAAO,KAAK,SAChB,CAUA,MAAM,SAAyB,CAC3B,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,UAAY,IAAA,EAAS,CACvD,CAGA,IAAI,KAA4B,CAC5B,OAAO,KAAK,QAChB,CAgBA,IAAI,EAAwE,CACxE,IAAM,EAAO,KAAK,UAAU,SAAW,KAAK,QAAQ,CAAK,CAAC,EAE1D,MADA,MAAK,UAAY,EAAK,UAAY,IAAA,EAAS,EACpC,CACX,CAQA,MAAc,QAAQ,EAAwE,CAC1F,GAAI,CAEA,OAAO,MADc,KAAK,SAAS,IAAI,KAAK,iBAAiB,CAAK,CAAC,CAEvE,OAAS,EAAK,CACV,MAAM,IAAI,EAAA,eAAe,qBAAsB,EAAc,UAAW,CAAE,MAAO,CAAI,CAAC,CAC1F,CACJ,CAgBA,iBAAyB,EAA+D,CACpF,IAAI,EAA+C,KACnD,IAAK,GAAM,CAAC,EAAM,KAAW,OAAO,QAAQ,CAAK,EAAG,CAChD,IAAM,EAAW,KAAK,YAAY,GAElC,GADI,IAAa,IAAA,IAAa,IAAa,EAAO,MAC9C,EAAE,EAAO,gBAAgB,cAAe,SAC5C,IAAM,EAAO,EAAA,WAAW,EAAO,KAAM,CAAQ,EACzC,IAAS,EAAO,OACpB,IAAc,CAAE,GAAG,CAAM,EACzB,EAAU,GAAQ,IAAI,EAAW,OAC7B,EACA,EACA,EAAO,IACX,EACJ,CACA,OAAO,GAAa,CACxB,CACJ"}
|
|
1
|
+
{"version":3,"file":"session.cjs","names":[],"sources":["../../../src/vision/core/session.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Thin wrapper around `onnxruntime-web` `InferenceSession` with typed metadata.\n */\n\nimport type * as ort from \"onnxruntime-web\";\nimport * as ortRuntime from \"onnxruntime-web\";\n\nimport { DEFAULT_TENSOR_TYPE, hasFloat16Array, tensorTypeFor, toFeedData } from \"./dtypes\";\nimport { InferenceError, ModelLoadError } from \"./exceptions\";\nimport { type DeclaredShape, declaredShapesFrom } from \"./graph\";\nimport { readModelInputTypes, readModelMetadata, readModelShapes } from \"./metadata\";\nimport {\n FALLBACK_PROVIDER,\n type ProviderSpec,\n detectProviders,\n providerName,\n resolveProviders,\n} from \"./providers\";\n\n/** Anything `InferenceSession.create` accepts. */\nexport type ModelSource = string | ArrayBufferLike | Uint8Array;\n\n/**\n * Metadata key naming the level a model was graph-optimized at offline.\n *\n * Written by the Python SDK's `optimize_model`; both test suites pin the same\n * string, so a rename on one side fails. See {@link OrtSession.create} for what\n * the session does when it finds it.\n */\nexport const GRAPH_OPTIMIZATION_KEY = \"ort_vision_sdk.graph_optimization\";\n\n/**\n * An 84-byte ONNX model — one `Identity` on a float `[1]` — used to start the runtime.\n *\n * Generated with `onnx.helper` (opset 13, IR 7, producer `ort-vision-sdk`).\n * See {@link warmRuntime} for why it exists.\n */\nconst RUNTIME_PROBE_MODEL =\n \"CAcSDm9ydC12aXNpb24tc2RrOjoKEAoBeBIBeSIISWRlbnRpdHkSBHdhcm1aDwoBeBIKCggIARIECgIIAWIPCgF5EgoKCAgBEgQKAggBQgQKABAN\";\n\n/** Runtime start-ups already begun on this page, keyed by provider names. */\nconst runtimeWarmups = new Map<string, Promise<void>>();\n\n/**\n * Start ONNX Runtime's backends for a provider list, once per page.\n *\n * ORT downloads and compiles its WebAssembly binary — 12.8 MB for the plain\n * WASM build, 25.9 MB for the one carrying WebGPU — inside the first\n * `InferenceSession.create`. {@link OrtSession.create} only reaches that call\n * after it has downloaded the model, so on a real network the two largest\n * downloads of a page load ran one after the other. Creating and releasing a\n * session on a tiny model while the real one downloads lets them overlap; the\n * real `create` then finds the runtime ready.\n *\n * A failure here is swallowed: the real `create` runs against the same runtime\n * and reports the same problem with the right model in the message.\n *\n * @param specs Providers the real session will use.\n * @returns Settles when the runtime is up, or when starting it failed.\n */\nfunction warmRuntime(specs: readonly ProviderSpec[]): Promise<void> {\n const key = specs.map(providerName).join(\",\");\n let pending = runtimeWarmups.get(key);\n if (pending === undefined) {\n pending = (async () => {\n try {\n const probe = Uint8Array.from(atob(RUNTIME_PROBE_MODEL), (c) => c.charCodeAt(0));\n const session = await ortRuntime.InferenceSession.create(probe, {\n executionProviders:\n specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n });\n await session.release();\n } catch {\n return;\n }\n })();\n runtimeWarmups.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Warn that a model optimized offline is about to run on WebGPU.\n *\n * `optimize_model` fuses operators for the CPU, which is what the WASM backend\n * runs. On WebGPU some of those fused nodes have no GPU kernel: on a\n * YOLO11n-seg, ONNX Runtime placed 2 nodes on the CPU for the optimized file\n * and none for the original, so every inference pays GPU↔CPU copies. The SDK\n * cannot swap the file, so it says which one to ship.\n */\nfunction warnPreOptimizedOnWebGpu(): void {\n console.warn(\n \"[@ort-vision-sdk/web] This model was pre-optimized by optimize_model, which targets the \" +\n \"WASM backend; on WebGPU some of its fused nodes fall back to the CPU. For WebGPU, ship \" +\n \"the original export instead.\",\n );\n}\n\n/**\n * Metadata key the Python SDK's `quantize_model` writes on an INT8 model.\n *\n * Mirrored by `QUANTIZATION_KEY` in the Python SDK; both test suites pin the\n * string. See {@link keepQuantizedOffWebGpu} for what a session does with it.\n */\nexport const QUANTIZATION_KEY = \"ort_vision_sdk.quantization\";\n\n/**\n * Drop `webgpu` from the providers of a model `quantize_model` produced.\n *\n * ONNX Runtime Web's WebGPU `DequantizeLinear` rejects the quantized bias such\n * a model carries — `scale and zero-point inputs must have the same rank` —\n * so the first `predict()` fails; and a variant with the bias left in float\n * ran but returned different detections than WASM for the same file. The\n * model is fine on WASM, which is also where INT8 pays (52.7 ms vs 68.4 ms on\n * a YOLO11n-seg), so the session runs there and says so.\n *\n * @param specs Providers that survived detection.\n * @param metadata The model's metadata map.\n * @returns `specs` without `webgpu` when the model is marked quantized; the\n * WASM fallback when nothing else is left.\n */\nfunction keepQuantizedOffWebGpu(\n specs: readonly ProviderSpec[],\n metadata: Readonly<Record<string, string>>,\n): ProviderSpec[] {\n if (metadata[QUANTIZATION_KEY] === undefined) return [...specs];\n const kept = specs.filter((spec) => providerName(spec) !== \"webgpu\");\n if (kept.length === specs.length) return kept;\n console.warn(\n `[@ort-vision-sdk/web] This model was quantized by quantize_model (${metadata[QUANTIZATION_KEY]}); ` +\n \"ONNX Runtime Web's WebGPU backend cannot run its quantized operators, so it runs on WASM.\",\n );\n return kept.length > 0 ? kept : [FALLBACK_PROVIDER];\n}\n\n/** Cache Storage bucket used when {@link OrtSessionOptions.cache} is `true`. */\nexport const DEFAULT_MODEL_CACHE = \"ort-vision-sdk-models\";\n\n/**\n * Fetch a model URL as bytes so its metadata can be read.\n *\n * Falls back to the URL itself when the fetch fails, letting ORT try its own\n * load path: losing the metadata map is a downgrade, but failing to load a model\n * that ORT could have fetched would be a regression.\n *\n * @param url Where the `.onnx` lives.\n * @param cacheName Cache Storage bucket to read from and fill, or `null` to\n * always go to the network.\n * @returns The model bytes, or the original URL when they could not be fetched.\n */\nasync function fetchModel(url: string, cacheName: string | null): Promise<Uint8Array | string> {\n const cache = cacheName === null ? null : await openCache(cacheName);\n if (cache !== null) {\n const hit = await cache.match(url).catch(() => undefined);\n if (hit !== undefined) return new Uint8Array(await hit.arrayBuffer());\n }\n try {\n const response = await fetch(url);\n if (!response.ok) {\n warnMetadataUnavailable(url, `HTTP ${response.status} ${response.statusText}`);\n return url;\n }\n const buffer = await response.arrayBuffer();\n if (cache !== null) await storeModel(cache, url, buffer);\n return new Uint8Array(buffer);\n } catch (err) {\n warnMetadataUnavailable(url, (err as Error).message);\n return url;\n }\n}\n\n/**\n * Put a model's bytes into the cache, never failing the load over it.\n *\n * Stores a fresh `Response` built from bytes already read rather than a\n * `clone()` of the network response: one read, and nothing that can throw\n * synchronously outside the guard. Awaited on purpose — a `put` left running\n * would keep its copy of the model reachable while ORT builds the session, the\n * same doubled peak {@link OrtSession.create} orders its reads to avoid.\n *\n * @param cache The open bucket.\n * @param url Cache key.\n * @param buffer The model.\n */\nasync function storeModel(cache: Cache, url: string, buffer: ArrayBuffer): Promise<void> {\n try {\n await cache.put(url, new Response(buffer));\n } catch {\n return;\n }\n}\n\n/**\n * Open a Cache Storage bucket, or report that there is none to open.\n *\n * Cache Storage only exists in secure contexts (HTTPS, `localhost`), and a\n * browser may refuse it outright — private windows, blocked site data, an\n * exhausted quota. None of that is worth failing a model load over: the model\n * is fetched from the network as if caching had not been asked for. A failed\n * `put` is swallowed for the same reason — see {@link storeModel}.\n *\n * @param name Bucket name.\n * @returns The cache, or `null` when this environment cannot provide one.\n */\nasync function openCache(name: string): Promise<Cache | null> {\n if (typeof caches === \"undefined\") return null;\n try {\n return await caches.open(name);\n } catch {\n return null;\n }\n}\n\n/**\n * Warn that a model's metadata could not be read, and say what that costs.\n *\n * The fallback itself is right — losing the metadata beats failing a load that\n * ORT could have completed on its own — but it used to be silent, and the\n * symptom it produces is remote from the cause: class names come back as\n * `class_0`, `class_1`, ... with nothing anywhere explaining why. Whoever hits\n * this needs to be told that passing `labels` is the way out.\n *\n * @param url The model URL that could not be fetched here.\n * @param reason What went wrong, as reported by `fetch`.\n */\nfunction warnMetadataUnavailable(url: string, reason: string): void {\n console.warn(\n `[@ort-vision-sdk/web] Could not fetch ${url} to read its metadata (${reason}). ` +\n \"Letting ONNX Runtime load it instead: the model will work, but its baked-in \" +\n \"class names are unavailable, so labels fall back to class_0, class_1, ... \" +\n \"Pass `labels` explicitly to name them.\",\n );\n}\n\nexport interface OrtSessionOptions {\n /**\n * Execution providers in preference order. `undefined` uses {@link DEFAULT_PROVIDERS}.\n *\n * Each entry is a name (`\"webgpu\"`, `\"wasm\"`) or ORT's config object for that\n * provider, which passes provider options through untouched —\n * `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`.\n *\n * Naming one explicitly also opts into a `console.warn` when this browser\n * cannot offer it, instead of falling back in silence.\n */\n readonly providers?: readonly ProviderSpec[];\n /**\n * Keep a URL model in the browser's Cache Storage between page loads.\n *\n * `true` uses the {@link DEFAULT_MODEL_CACHE} bucket; a string names the\n * bucket. A later `create` with the same URL reads the bytes from the cache\n * instead of the network — for a model of several megabytes, the bulk of\n * what a returning visitor waits for. Defaults to `false`.\n *\n * The URL is the cache key and nothing expires it: publish a changed model\n * under a new URL (`yolo.v2.onnx`, `?v=2`) or a new bucket name, or delete\n * the bucket with `caches.delete(name)`. Ignored for models passed as bytes,\n * and silently skipped where Cache Storage is unavailable (non-secure\n * contexts, blocked site data).\n */\n readonly cache?: boolean | string;\n /** Optional ORT session options forwarded to `InferenceSession.create`. */\n readonly sessionOptions?: ort.InferenceSession.SessionOptions;\n /**\n * Whether to read the model's custom metadata map (`names`, `task`, `imgsz`).\n * Defaults to `true`.\n *\n * The runtime does not expose that map, so it is read from the file itself —\n * which means a URL model is fetched here and handed to ORT as bytes instead\n * of letting ORT fetch it. That is the same single download either way, and\n * it is what lets a task resolve its labels off the model. Set to `false` to\n * keep the URL path untouched (unless {@link cache} is set, which needs the\n * bytes) and leave {@link OrtSession.metadata} empty.\n *\n * `false` is also the escape hatch when a device cannot afford the bytes: the\n * fetched buffer is dropped before ORT builds the graph (see\n * {@link OrtSession.create}), but ORT's own load path still keeps the model out\n * of reach of anything the SDK holds. A session built this way resolves its\n * input size from the graph as usual — only the class names are lost, so a\n * caller taking this route has to pass `labels` itself.\n */\n readonly readMetadata?: boolean;\n}\n\n/**\n * Warn when a provider named explicitly by the caller is not going to run.\n *\n * Only explicit requests are worth a warning. The default list exists precisely\n * so that falling from `webgpu` to `wasm` is the expected outcome — but a caller\n * who wrote `providers: [\"webgpu\"]` and lands on WASM has a page several times\n * slower than intended and nothing in the console to explain it.\n *\n * @param requested Providers that were asked for.\n * @param effective Providers that survived capability detection.\n */\nfunction warnOnDroppedProviders(requested: readonly string[], effective: readonly string[]): void {\n const dropped = requested.filter((provider) => !effective.includes(provider));\n if (dropped.length === 0) {\n return;\n }\n console.warn(\n `This browser cannot offer the requested execution provider(s) ${JSON.stringify(dropped)}; ` +\n `the session will run on ${JSON.stringify(effective)}. Inference still produces correct ` +\n \"results, on the fallback provider.\",\n );\n}\n\n/**\n * Name the tensor type of every graph input, straight from the model bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → tensor type name. Empty when the file carries no\n * readable graph, which callers read as \"assume float32\".\n */\nfunction declaredInputTypes(model: Uint8Array | ArrayBufferLike): Readonly<Record<string, string>> {\n const declared = readModelInputTypes(model);\n const named: Record<string, string> = {};\n for (const [name, elemType] of Object.entries(declared)) {\n named[name] = tensorTypeFor(elemType);\n }\n return named;\n}\n\n/**\n * Warn when the model's bytes were in hand but no input type came back.\n *\n * Every ONNX graph declares at least one input, so an empty result from bytes\n * means the reader failed, not that the model said nothing. Without this the\n * failure is invisible: the session falls back to float32, which is right for\n * most models and wrong for exactly the half-precision ones this reader exists\n * to support — so it looks like nothing is broken until a `predict()` throws\n * `Unexpected input data type`. That is how a 1 MB ceiling on the graph\n * descent shipped in 0.9.0 and reached a consumer.\n */\nfunction warnOnUnreadableTypes(): void {\n console.warn(\n \"Could not read any input type from this model's bytes; feeds will be built as float32. \" +\n \"A half-precision model will fail at inference with 'Unexpected input data type'. \" +\n \"Please report this with the model that produced it.\",\n );\n}\n\n/**\n * Refuse a half-precision model in an environment that cannot feed one.\n *\n * ORT requires a real `Float16Array` for a `float16` tensor — the same bits in\n * a `Uint16Array` are rejected — and not every browser has one yet. Without\n * this check the session builds happily and the first `predict()` throws from\n * inside the preprocessing, which is both later and further from the cause.\n *\n * @param inputTypes Tensor type per input name.\n * @throws {@link ModelLoadError} when the graph wants half precision and the\n * runtime has no `Float16Array`.\n */\nfunction assertFeedableTypes(inputTypes: Readonly<Record<string, string>>): void {\n const half = Object.entries(inputTypes).filter(([, type]) => type === \"float16\");\n if (half.length === 0 || hasFloat16Array()) return;\n const names = half.map(([name]) => name).join(\", \");\n throw new ModelLoadError(\n `This model declares half-precision input(s) [${names}], but this environment has no ` +\n \"Float16Array, which ONNX Runtime requires for a float16 tensor. Use a float32 export \" +\n \"of the model, or run in a browser that supports Float16Array.\",\n );\n}\n\n/**\n * Wrap an ONNX Runtime Web `InferenceSession` with convenient metadata access.\n *\n * The wrapper exposes input/output names and the shapes the graph declares,\n * manages execution-provider selection, provides a typed {@link OrtSession.run}\n * method, and releases the native session through {@link OrtSession.release}.\n */\nexport class OrtSession {\n private constructor(\n private readonly _session: ort.InferenceSession,\n /**\n * Execution providers this session is expected to run on.\n *\n * The requested list narrowed to what this browser can actually offer — a\n * `webgpu` entry survives only where an adapter exists. Best-effort: ORT-Web\n * exposes no way to ask which provider a session ended up on, so an entry\n * here means \"not ruled out\", not \"confirmed\". See\n * {@link requestedProviders} for what was asked for.\n *\n * When nothing survives — a caller asking for `webgpu` alone on a device\n * without it — this falls back to {@link FALLBACK_PROVIDER}, which ORT-Web\n * can always run. Handing ORT the unsatisfiable list instead makes\n * `InferenceSession.create` reject with \"no available backend found\", so the\n * page gets no inference at all rather than the slow-but-working fallback\n * the `console.warn` describes. Measured in a real Chromium, where\n * `navigator.gpu` exists but yields no adapter.\n */\n public readonly providers: readonly string[],\n private readonly _metadata: Readonly<Record<string, string>>,\n /**\n * Execution providers that were asked for, after defaults were applied.\n *\n * Kept separate because ORT-Web falls back silently: a page that asks for\n * `webgpu` on a device without it runs on WASM and is told nothing.\n */\n public readonly requestedProviders: readonly string[],\n /**\n * Tensor type each input declares, keyed by input name.\n *\n * Read from the model file, not from the session: `inputMetadata` is\n * `undefined` on `onnxruntime-web` 1.20.1. Empty when the bytes were never\n * in hand — a URL loaded with `readMetadata: false` — in which case every\n * feed is built as float32, the behaviour before this existed.\n */\n private readonly _inputTypes: Readonly<Record<string, string>> = {},\n /**\n * Shapes the model file declares, keyed by value name.\n *\n * The fallback for {@link inputShapes} and {@link outputShapes} when the\n * runtime reports none, which `onnxruntime-web` does below 1.22. Empty when\n * the bytes were never in hand (a URL loaded with `readMetadata: false`).\n */\n private readonly _fileShapes: {\n readonly inputs: Readonly<Record<string, DeclaredShape>>;\n readonly outputs: Readonly<Record<string, DeclaredShape>>;\n } = { inputs: {}, outputs: {} },\n ) {}\n\n /**\n * Tail of the run queue: settles when the latest queued run has finished.\n *\n * See {@link run} for why runs are serialized.\n */\n private _runQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Load an ONNX model into an ORT inference session.\n *\n * The metadata map is read **before** the session is built, and that order is\n * load-bearing on memory-constrained devices. ORT copies the model into its\n * WASM heap and then allocates the graph and the weights on top of that copy;\n * a `readModelMetadata` call placed after `InferenceSession.create` keeps the\n * JavaScript-side buffer reachable across the whole build, so a 5 MB model\n * costs 5 MB of JS heap plus 5 MB of WASM heap plus the weights at the same\n * instant. Reading first makes the buffer collectable as soon as ORT has copied\n * it — on a phone that was the difference between a session and\n * `Can't create a session. failed to allocate a buffer of size N`.\n *\n * The provider probe and the model download run concurrently: neither\n * depends on the other, and on a real GPU `requestAdapter()` is not free.\n * When the model is downloaded here, ORT's runtime is started alongside the\n * download too — see {@link warmRuntime}.\n *\n * A model whose metadata carries {@link GRAPH_OPTIMIZATION_KEY} was already\n * optimized offline by the Python SDK's `optimize_model`, so it is loaded\n * with `graphOptimizationLevel: \"disabled\"` instead of paying the optimizer a\n * second time — measured on a YOLO11n-seg under WASM, 29 ms of session\n * creation down to 12 ms with unchanged inference time. An explicit\n * `graphOptimizationLevel` in `sessionOptions` always wins. The mark is read\n * with the rest of the metadata, so `readMetadata: false` skips it too.\n *\n * @param model Either a URL string, or a `Uint8Array`/`ArrayBuffer` containing the model bytes.\n * @param options Provider list, pass-through `SessionOptions`, and whether to\n * read the model's metadata map (see {@link OrtSessionOptions.readMetadata}).\n * @throws {@link ModelLoadError} if the model cannot be loaded.\n */\n static async create(model: ModelSource, options: OrtSessionOptions = {}): Promise<OrtSession> {\n const requested = resolveProviders(options.providers);\n const wantsMetadata = options.readMetadata !== false;\n const cacheName =\n options.cache === true ? DEFAULT_MODEL_CACHE : options.cache ? options.cache : null;\n const shouldFetch = typeof model === \"string\" && (wantsMetadata || cacheName !== null);\n const detection = detectProviders(requested).then((detected) =>\n detected.length > 0 ? detected : [FALLBACK_PROVIDER],\n );\n const [detected, source] = await Promise.all([\n detection,\n shouldFetch ? fetchModel(model, cacheName) : Promise.resolve(model),\n shouldFetch ? detection.then(warmRuntime) : Promise.resolve(),\n ]);\n const metadata =\n wantsMetadata && typeof source !== \"string\" ? readModelMetadata(source) : {};\n const specs = keepQuantizedOffWebGpu(detected, metadata);\n const requestedNames = requested.map(providerName);\n const providers = specs.map(providerName);\n if (options.providers !== undefined && options.providers.length > 0) {\n warnOnDroppedProviders(requestedNames, detected.map(providerName));\n }\n if (metadata[GRAPH_OPTIMIZATION_KEY] !== undefined && providers.includes(\"webgpu\")) {\n warnPreOptimizedOnWebGpu();\n }\n const preOptimized =\n metadata[GRAPH_OPTIMIZATION_KEY] !== undefined &&\n options.sessionOptions?.graphOptimizationLevel === undefined;\n const sessionOptions: ort.InferenceSession.SessionOptions = {\n ...(preOptimized ? { graphOptimizationLevel: \"disabled\" as const } : {}),\n ...(options.sessionOptions ?? {}),\n executionProviders: specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n };\n const inputTypes = typeof source !== \"string\" ? declaredInputTypes(source) : {};\n const fileShapes =\n typeof source !== \"string\" ? readModelShapes(source) : { inputs: {}, outputs: {} };\n if (typeof source !== \"string\" && Object.keys(inputTypes).length === 0) {\n warnOnUnreadableTypes();\n }\n assertFeedableTypes(inputTypes);\n\n let session: ort.InferenceSession;\n try {\n if (typeof source === \"string\") {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else if (source instanceof Uint8Array) {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else {\n session = await ortRuntime.InferenceSession.create(\n source as ArrayBuffer,\n sessionOptions,\n );\n }\n } catch (err) {\n throw new ModelLoadError(`Failed to load ONNX model: ${(err as Error).message}`, {\n cause: err,\n });\n }\n\n return new OrtSession(session, providers, metadata, requestedNames, inputTypes, fileShapes);\n }\n\n /**\n * Tensor type each input declares, in declaration order.\n *\n * `\"float32\"` for a normal export, `\"float16\"` for one exported with\n * `half=True`. ORT matches a feed's type against this exactly, so the tasks\n * read it and convert at the feed boundary.\n */\n get inputDtypes(): readonly string[] {\n return this.inputNames.map((name) => this._inputTypes[name] ?? DEFAULT_TENSOR_TYPE);\n }\n\n /** Tensor type the first input declares. */\n get inputDtype(): string {\n return this._inputTypes[this.inputName] ?? DEFAULT_TENSOR_TYPE;\n }\n\n /** Names of the model's inputs, in declaration order. */\n get inputNames(): readonly string[] {\n return this._session.inputNames;\n }\n\n /** Name of the first (and usually only) input. */\n get inputName(): string {\n const name = this._session.inputNames[0];\n if (name === undefined) {\n throw new InferenceError(\"Model has no inputs.\");\n }\n return name;\n }\n\n /** Names of the model's outputs, in declaration order. */\n get outputNames(): readonly string[] {\n return this._session.outputNames;\n }\n\n /**\n * Shapes the graph declares for its inputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Read from the runtime when it\n * reports them (`onnxruntime-web` >= 1.22), otherwise from the model file. An\n * empty shape means neither source declared one: a non-tensor input, or a URL\n * model loaded with `readMetadata: false` on a runtime that reports nothing.\n */\n get inputShapes(): readonly DeclaredShape[] {\n return this._shapesOf(\n this._session.inputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n this._session.inputNames,\n this._fileShapes.inputs,\n );\n }\n\n /**\n * Shape the graph declares for its first input, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get inputShape(): DeclaredShape {\n return this.inputShapes[0] ?? [];\n }\n\n /**\n * Shapes the graph declares for its outputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Reading them is how a task can\n * tell how many classes a head emits without being told. Same sources as\n * {@link inputShapes}.\n */\n get outputShapes(): readonly DeclaredShape[] {\n return this._shapesOf(\n this._session.outputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n this._session.outputNames,\n this._fileShapes.outputs,\n );\n }\n\n /**\n * Pick the runtime's declared shapes, or the file's when the runtime has none.\n *\n * @param metadata What the runtime reports, `undefined` below 1.22.\n * @param names The session's value names, in its own order.\n * @param fromFile Shapes the model file declares, keyed by name.\n * @returns One shape per name, in the session's order.\n */\n private _shapesOf(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n names: readonly string[],\n fromFile: Readonly<Record<string, DeclaredShape>>,\n ): readonly DeclaredShape[] {\n const reported = declaredShapesFrom(metadata);\n if (reported.length > 0) return reported;\n return names.map((name) => fromFile[name] ?? []);\n }\n\n /**\n * Shape the graph declares for its first output, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get outputShape(): DeclaredShape {\n return this.outputShapes[0] ?? [];\n }\n\n /**\n * The model's custom metadata map — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export.\n *\n * Read from the model's bytes at load time, since the runtime does not expose\n * it. Empty when the session was created with `readMetadata: false`, from a\n * URL that could not be fetched here, or from a model carrying no metadata.\n */\n get metadata(): Readonly<Record<string, string>> {\n return this._metadata;\n }\n\n /**\n * Release the native session and free its memory.\n *\n * Call it when a session is discarded while the page lives on — rebuilding a\n * task at a different input size, swapping in a newer model. A failure from\n * the runtime is ignored: a session being torn down has nothing left to fail\n * at, and the caller is already moving on.\n */\n async release(): Promise<void> {\n await this._session.release().catch(() => undefined);\n }\n\n /** The underlying `onnxruntime-web` session, for advanced use cases. */\n get raw(): ort.InferenceSession {\n return this._session;\n }\n\n /**\n * Run inference and return all outputs.\n *\n * Runs on one session are serialized. ONNX Runtime Web refuses a second\n * `run` while one is in flight — it rejects with `Session already started` —\n * so two overlapping `predict()` calls on the same task used to fail. Queued\n * here, they overlap where they can: while one run executes (in a worker,\n * with `env.wasm.proxy`, or on the GPU), the next `predict()` decodes and\n * preprocesses its frame and only waits for its turn at the runtime. A run\n * that fails does not block the ones behind it.\n *\n * @param feeds Map of input name to `ort.Tensor`. Keys must match {@link inputNames}.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n run(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n const turn = this._runQueue.then(() => this._runNow(feeds));\n this._runQueue = turn.catch(() => undefined);\n return turn;\n }\n\n /**\n * Execute one run immediately; only {@link run}'s queue calls this.\n *\n * @param feeds Map of input name to `ort.Tensor`.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n private async _runNow(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n try {\n const result = await this._session.run(this._asDeclaredTypes(feeds));\n return result as Record<string, ort.Tensor>;\n } catch (err) {\n throw new InferenceError(`Inference failed: ${(err as Error).message}`, { cause: err });\n }\n }\n\n /**\n * Rebuild any feed whose type does not match what its input declares.\n *\n * ORT matches feed types against the graph exactly: a float32 tensor against\n * a `half=True` export fails the run with `Unexpected input data type`. Every\n * preprocessing path in this SDK produces `Float32Array`, on purpose — the\n * normalization arithmetic belongs in single precision — so the conversion\n * happens here, once, at the only boundary all of them pass through. A feed\n * that already carries the declared type is handed on untouched, so a caller\n * building its own half tensor pays nothing.\n *\n * @param feeds The tensors to run with.\n * @returns The same mapping, with mismatched float32 feeds converted.\n */\n private _asDeclaredTypes(feeds: Record<string, ort.Tensor>): Record<string, ort.Tensor> {\n let converted: Record<string, ort.Tensor> | null = null;\n for (const [name, tensor] of Object.entries(feeds)) {\n const declared = this._inputTypes[name];\n if (declared === undefined || declared === tensor.type) continue;\n if (!(tensor.data instanceof Float32Array)) continue;\n const data = toFeedData(tensor.data, declared);\n if (data === tensor.data) continue;\n converted ??= { ...feeds };\n converted[name] = new ortRuntime.Tensor(\n declared as \"float16\",\n data as unknown as Float32Array,\n tensor.dims as number[],\n );\n }\n return converted ?? feeds;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
import { InferenceError as e, ModelLoadError as t } from "./exceptions.js";
|
|
2
2
|
import { hasFloat16Array as n, tensorTypeFor as r, toFeedData as i } from "./dtypes.js";
|
|
3
3
|
import { declaredShapesFrom as a } from "./graph.js";
|
|
4
|
-
import { readModelInputTypes as o, readModelMetadata as s } from "./metadata.js";
|
|
5
|
-
import { FALLBACK_PROVIDER as
|
|
6
|
-
import * as
|
|
4
|
+
import { readModelInputTypes as o, readModelMetadata as s, readModelShapes as c } from "./metadata.js";
|
|
5
|
+
import { FALLBACK_PROVIDER as l, detectProviders as u, providerName as d, resolveProviders as f } from "./providers.js";
|
|
6
|
+
import * as p from "onnxruntime-web";
|
|
7
7
|
//#region src/vision/core/session.ts
|
|
8
|
-
var
|
|
9
|
-
function
|
|
10
|
-
let t = e.map(
|
|
8
|
+
var m = "ort_vision_sdk.graph_optimization", h = "CAcSDm9ydC12aXNpb24tc2RrOjoKEAoBeBIBeSIISWRlbnRpdHkSBHdhcm1aDwoBeBIKCggIARIECgIIAWIPCgF5EgoKCAgBEgQKAggBQgQKABAN", g = /* @__PURE__ */ new Map();
|
|
9
|
+
function _(e) {
|
|
10
|
+
let t = e.map(d).join(","), n = g.get(t);
|
|
11
11
|
return n === void 0 && (n = (async () => {
|
|
12
12
|
try {
|
|
13
|
-
let t = Uint8Array.from(atob(
|
|
14
|
-
await (await
|
|
13
|
+
let t = Uint8Array.from(atob(h), (e) => e.charCodeAt(0));
|
|
14
|
+
await (await p.InferenceSession.create(t, { executionProviders: e })).release();
|
|
15
15
|
} catch {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
})(),
|
|
18
|
+
})(), g.set(t, n)), n;
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function v() {
|
|
21
21
|
console.warn("[@ort-vision-sdk/web] This model was pre-optimized by optimize_model, which targets the WASM backend; on WebGPU some of its fused nodes fall back to the CPU. For WebGPU, ship the original export instead.");
|
|
22
22
|
}
|
|
23
|
-
var
|
|
24
|
-
function
|
|
23
|
+
var y = "ort_vision_sdk.quantization";
|
|
24
|
+
function b(e, t) {
|
|
25
25
|
if (t["ort_vision_sdk.quantization"] === void 0) return [...e];
|
|
26
|
-
let n = e.filter((e) =>
|
|
27
|
-
return n.length === e.length ? n : (console.warn(`[@ort-vision-sdk/web] This model was quantized by quantize_model (${t[
|
|
26
|
+
let n = e.filter((e) => d(e) !== "webgpu");
|
|
27
|
+
return n.length === e.length ? n : (console.warn(`[@ort-vision-sdk/web] This model was quantized by quantize_model (${t[y]}); ONNX Runtime Web's WebGPU backend cannot run its quantized operators, so it runs on WASM.`), n.length > 0 ? n : [l]);
|
|
28
28
|
}
|
|
29
|
-
var
|
|
30
|
-
async function
|
|
31
|
-
let n = t === null ? null : await
|
|
29
|
+
var x = "ort-vision-sdk-models";
|
|
30
|
+
async function S(e, t) {
|
|
31
|
+
let n = t === null ? null : await w(t);
|
|
32
32
|
if (n !== null) {
|
|
33
33
|
let t = await n.match(e).catch(() => void 0);
|
|
34
34
|
if (t !== void 0) return new Uint8Array(await t.arrayBuffer());
|
|
35
35
|
}
|
|
36
36
|
try {
|
|
37
37
|
let t = await fetch(e);
|
|
38
|
-
if (!t.ok) return
|
|
38
|
+
if (!t.ok) return T(e, `HTTP ${t.status} ${t.statusText}`), e;
|
|
39
39
|
let r = await t.arrayBuffer();
|
|
40
|
-
return n !== null && await
|
|
40
|
+
return n !== null && await C(n, e, r), new Uint8Array(r);
|
|
41
41
|
} catch (t) {
|
|
42
|
-
return
|
|
42
|
+
return T(e, t.message), e;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
async function
|
|
45
|
+
async function C(e, t, n) {
|
|
46
46
|
try {
|
|
47
47
|
await e.put(t, new Response(n));
|
|
48
48
|
} catch {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
async function
|
|
52
|
+
async function w(e) {
|
|
53
53
|
if (typeof caches > "u") return null;
|
|
54
54
|
try {
|
|
55
55
|
return await caches.open(e);
|
|
@@ -57,57 +57,64 @@ async function C(e) {
|
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
function
|
|
60
|
+
function T(e, t) {
|
|
61
61
|
console.warn(`[@ort-vision-sdk/web] Could not fetch ${e} to read its metadata (${t}). Letting ONNX Runtime load it instead: the model will work, but its baked-in class names are unavailable, so labels fall back to class_0, class_1, ... Pass \`labels\` explicitly to name them.`);
|
|
62
62
|
}
|
|
63
|
-
function
|
|
63
|
+
function E(e, t) {
|
|
64
64
|
let n = e.filter((e) => !t.includes(e));
|
|
65
65
|
n.length !== 0 && console.warn(`This browser cannot offer the requested execution provider(s) ${JSON.stringify(n)}; the session will run on ${JSON.stringify(t)}. Inference still produces correct results, on the fallback provider.`);
|
|
66
66
|
}
|
|
67
|
-
function
|
|
67
|
+
function D(e) {
|
|
68
68
|
let t = o(e), n = {};
|
|
69
69
|
for (let [e, i] of Object.entries(t)) n[e] = r(i);
|
|
70
70
|
return n;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function O() {
|
|
73
73
|
console.warn("Could not read any input type from this model's bytes; feeds will be built as float32. A half-precision model will fail at inference with 'Unexpected input data type'. Please report this with the model that produced it.");
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function k(e) {
|
|
76
76
|
let r = Object.entries(e).filter(([, e]) => e === "float16");
|
|
77
77
|
if (r.length === 0 || n()) return;
|
|
78
78
|
let i = r.map(([e]) => e).join(", ");
|
|
79
79
|
throw new t(`This model declares half-precision input(s) [${i}], but this environment has no Float16Array, which ONNX Runtime requires for a float16 tensor. Use a float32 export of the model, or run in a browser that supports Float16Array.`);
|
|
80
80
|
}
|
|
81
|
-
var
|
|
81
|
+
var A = class n {
|
|
82
82
|
_session;
|
|
83
83
|
providers;
|
|
84
84
|
_metadata;
|
|
85
85
|
requestedProviders;
|
|
86
86
|
_inputTypes;
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
_fileShapes;
|
|
88
|
+
constructor(e, t, n, r, i = {}, a = {
|
|
89
|
+
inputs: {},
|
|
90
|
+
outputs: {}
|
|
91
|
+
}) {
|
|
92
|
+
this._session = e, this.providers = t, this._metadata = n, this.requestedProviders = r, this._inputTypes = i, this._fileShapes = a;
|
|
89
93
|
}
|
|
90
94
|
_runQueue = Promise.resolve();
|
|
91
95
|
static async create(e, r = {}) {
|
|
92
|
-
let i =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
]),
|
|
97
|
-
r.providers !== void 0 && r.providers.length > 0 && T
|
|
98
|
-
let
|
|
99
|
-
...
|
|
96
|
+
let i = f(r.providers), a = r.readMetadata !== !1, o = r.cache === !0 ? x : r.cache ? r.cache : null, m = typeof e == "string" && (a || o !== null), h = u(i).then((e) => e.length > 0 ? e : [l]), [g, y] = await Promise.all([
|
|
97
|
+
h,
|
|
98
|
+
m ? S(e, o) : Promise.resolve(e),
|
|
99
|
+
m ? h.then(_) : Promise.resolve()
|
|
100
|
+
]), C = a && typeof y != "string" ? s(y) : {}, w = b(g, C), T = i.map(d), A = w.map(d);
|
|
101
|
+
r.providers !== void 0 && r.providers.length > 0 && E(T, g.map(d)), C["ort_vision_sdk.graph_optimization"] !== void 0 && A.includes("webgpu") && v();
|
|
102
|
+
let j = {
|
|
103
|
+
...C["ort_vision_sdk.graph_optimization"] !== void 0 && r.sessionOptions?.graphOptimizationLevel === void 0 ? { graphOptimizationLevel: "disabled" } : {},
|
|
100
104
|
...r.sessionOptions ?? {},
|
|
101
|
-
executionProviders:
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
executionProviders: w
|
|
106
|
+
}, M = typeof y == "string" ? {} : D(y), N = typeof y == "string" ? {
|
|
107
|
+
inputs: {},
|
|
108
|
+
outputs: {}
|
|
109
|
+
} : c(y);
|
|
110
|
+
typeof y != "string" && Object.keys(M).length === 0 && O(), k(M);
|
|
111
|
+
let P;
|
|
105
112
|
try {
|
|
106
|
-
|
|
113
|
+
P = (typeof y == "string" || y instanceof Uint8Array, await p.InferenceSession.create(y, j));
|
|
107
114
|
} catch (e) {
|
|
108
115
|
throw new t(`Failed to load ONNX model: ${e.message}`, { cause: e });
|
|
109
116
|
}
|
|
110
|
-
return new n(
|
|
117
|
+
return new n(P, A, C, T, M, N);
|
|
111
118
|
}
|
|
112
119
|
get inputDtypes() {
|
|
113
120
|
return this.inputNames.map((e) => this._inputTypes[e] ?? "float32");
|
|
@@ -127,13 +134,17 @@ var k = class n {
|
|
|
127
134
|
return this._session.outputNames;
|
|
128
135
|
}
|
|
129
136
|
get inputShapes() {
|
|
130
|
-
return
|
|
137
|
+
return this._shapesOf(this._session.inputMetadata, this._session.inputNames, this._fileShapes.inputs);
|
|
131
138
|
}
|
|
132
139
|
get inputShape() {
|
|
133
140
|
return this.inputShapes[0] ?? [];
|
|
134
141
|
}
|
|
135
142
|
get outputShapes() {
|
|
136
|
-
return
|
|
143
|
+
return this._shapesOf(this._session.outputMetadata, this._session.outputNames, this._fileShapes.outputs);
|
|
144
|
+
}
|
|
145
|
+
_shapesOf(e, t, n) {
|
|
146
|
+
let r = a(e);
|
|
147
|
+
return r.length > 0 ? r : t.map((e) => n[e] ?? []);
|
|
137
148
|
}
|
|
138
149
|
get outputShape() {
|
|
139
150
|
return this.outputShapes[0] ?? [];
|
|
@@ -164,12 +175,12 @@ var k = class n {
|
|
|
164
175
|
let a = this._inputTypes[n];
|
|
165
176
|
if (a === void 0 || a === r.type || !(r.data instanceof Float32Array)) continue;
|
|
166
177
|
let o = i(r.data, a);
|
|
167
|
-
o !== r.data && (t ??= { ...e }, t[n] = new
|
|
178
|
+
o !== r.data && (t ??= { ...e }, t[n] = new p.Tensor(a, o, r.dims));
|
|
168
179
|
}
|
|
169
180
|
return t ?? e;
|
|
170
181
|
}
|
|
171
182
|
};
|
|
172
183
|
//#endregion
|
|
173
|
-
export {
|
|
184
|
+
export { x as DEFAULT_MODEL_CACHE, m as GRAPH_OPTIMIZATION_KEY, A as OrtSession, y as QUANTIZATION_KEY };
|
|
174
185
|
|
|
175
186
|
//# sourceMappingURL=session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","names":[],"sources":["../../../src/vision/core/session.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Thin wrapper around `onnxruntime-web` `InferenceSession` with typed metadata.\n */\n\nimport type * as ort from \"onnxruntime-web\";\nimport * as ortRuntime from \"onnxruntime-web\";\n\nimport { DEFAULT_TENSOR_TYPE, hasFloat16Array, tensorTypeFor, toFeedData } from \"./dtypes\";\nimport { InferenceError, ModelLoadError } from \"./exceptions\";\nimport { type DeclaredShape, declaredShapesFrom } from \"./graph\";\nimport { readModelInputTypes, readModelMetadata } from \"./metadata\";\nimport {\n FALLBACK_PROVIDER,\n type ProviderSpec,\n detectProviders,\n providerName,\n resolveProviders,\n} from \"./providers\";\n\n/** Anything `InferenceSession.create` accepts. */\nexport type ModelSource = string | ArrayBufferLike | Uint8Array;\n\n/**\n * Metadata key naming the level a model was graph-optimized at offline.\n *\n * Written by the Python SDK's `optimize_model`; both test suites pin the same\n * string, so a rename on one side fails. See {@link OrtSession.create} for what\n * the session does when it finds it.\n */\nexport const GRAPH_OPTIMIZATION_KEY = \"ort_vision_sdk.graph_optimization\";\n\n/**\n * An 84-byte ONNX model — one `Identity` on a float `[1]` — used to start the runtime.\n *\n * Generated with `onnx.helper` (opset 13, IR 7, producer `ort-vision-sdk`).\n * See {@link warmRuntime} for why it exists.\n */\nconst RUNTIME_PROBE_MODEL =\n \"CAcSDm9ydC12aXNpb24tc2RrOjoKEAoBeBIBeSIISWRlbnRpdHkSBHdhcm1aDwoBeBIKCggIARIECgIIAWIPCgF5EgoKCAgBEgQKAggBQgQKABAN\";\n\n/** Runtime start-ups already begun on this page, keyed by provider names. */\nconst runtimeWarmups = new Map<string, Promise<void>>();\n\n/**\n * Start ONNX Runtime's backends for a provider list, once per page.\n *\n * ORT downloads and compiles its WebAssembly binary — 12.8 MB for the plain\n * WASM build, 25.9 MB for the one carrying WebGPU — inside the first\n * `InferenceSession.create`. {@link OrtSession.create} only reaches that call\n * after it has downloaded the model, so on a real network the two largest\n * downloads of a page load ran one after the other. Creating and releasing a\n * session on a tiny model while the real one downloads lets them overlap; the\n * real `create` then finds the runtime ready.\n *\n * A failure here is swallowed: the real `create` runs against the same runtime\n * and reports the same problem with the right model in the message.\n *\n * @param specs Providers the real session will use.\n * @returns Settles when the runtime is up, or when starting it failed.\n */\nfunction warmRuntime(specs: readonly ProviderSpec[]): Promise<void> {\n const key = specs.map(providerName).join(\",\");\n let pending = runtimeWarmups.get(key);\n if (pending === undefined) {\n pending = (async () => {\n try {\n const probe = Uint8Array.from(atob(RUNTIME_PROBE_MODEL), (c) => c.charCodeAt(0));\n const session = await ortRuntime.InferenceSession.create(probe, {\n executionProviders:\n specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n });\n await session.release();\n } catch {\n return;\n }\n })();\n runtimeWarmups.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Warn that a model optimized offline is about to run on WebGPU.\n *\n * `optimize_model` fuses operators for the CPU, which is what the WASM backend\n * runs. On WebGPU some of those fused nodes have no GPU kernel: on a\n * YOLO11n-seg, ONNX Runtime placed 2 nodes on the CPU for the optimized file\n * and none for the original, so every inference pays GPU↔CPU copies. The SDK\n * cannot swap the file, so it says which one to ship.\n */\nfunction warnPreOptimizedOnWebGpu(): void {\n console.warn(\n \"[@ort-vision-sdk/web] This model was pre-optimized by optimize_model, which targets the \" +\n \"WASM backend; on WebGPU some of its fused nodes fall back to the CPU. For WebGPU, ship \" +\n \"the original export instead.\",\n );\n}\n\n/**\n * Metadata key the Python SDK's `quantize_model` writes on an INT8 model.\n *\n * Mirrored by `QUANTIZATION_KEY` in the Python SDK; both test suites pin the\n * string. See {@link keepQuantizedOffWebGpu} for what a session does with it.\n */\nexport const QUANTIZATION_KEY = \"ort_vision_sdk.quantization\";\n\n/**\n * Drop `webgpu` from the providers of a model `quantize_model` produced.\n *\n * ONNX Runtime Web's WebGPU `DequantizeLinear` rejects the quantized bias such\n * a model carries — `scale and zero-point inputs must have the same rank` —\n * so the first `predict()` fails; and a variant with the bias left in float\n * ran but returned different detections than WASM for the same file. The\n * model is fine on WASM, which is also where INT8 pays (52.7 ms vs 68.4 ms on\n * a YOLO11n-seg), so the session runs there and says so.\n *\n * @param specs Providers that survived detection.\n * @param metadata The model's metadata map.\n * @returns `specs` without `webgpu` when the model is marked quantized; the\n * WASM fallback when nothing else is left.\n */\nfunction keepQuantizedOffWebGpu(\n specs: readonly ProviderSpec[],\n metadata: Readonly<Record<string, string>>,\n): ProviderSpec[] {\n if (metadata[QUANTIZATION_KEY] === undefined) return [...specs];\n const kept = specs.filter((spec) => providerName(spec) !== \"webgpu\");\n if (kept.length === specs.length) return kept;\n console.warn(\n `[@ort-vision-sdk/web] This model was quantized by quantize_model (${metadata[QUANTIZATION_KEY]}); ` +\n \"ONNX Runtime Web's WebGPU backend cannot run its quantized operators, so it runs on WASM.\",\n );\n return kept.length > 0 ? kept : [FALLBACK_PROVIDER];\n}\n\n/** Cache Storage bucket used when {@link OrtSessionOptions.cache} is `true`. */\nexport const DEFAULT_MODEL_CACHE = \"ort-vision-sdk-models\";\n\n/**\n * Fetch a model URL as bytes so its metadata can be read.\n *\n * Falls back to the URL itself when the fetch fails, letting ORT try its own\n * load path: losing the metadata map is a downgrade, but failing to load a model\n * that ORT could have fetched would be a regression.\n *\n * @param url Where the `.onnx` lives.\n * @param cacheName Cache Storage bucket to read from and fill, or `null` to\n * always go to the network.\n * @returns The model bytes, or the original URL when they could not be fetched.\n */\nasync function fetchModel(url: string, cacheName: string | null): Promise<Uint8Array | string> {\n const cache = cacheName === null ? null : await openCache(cacheName);\n if (cache !== null) {\n const hit = await cache.match(url).catch(() => undefined);\n if (hit !== undefined) return new Uint8Array(await hit.arrayBuffer());\n }\n try {\n const response = await fetch(url);\n if (!response.ok) {\n warnMetadataUnavailable(url, `HTTP ${response.status} ${response.statusText}`);\n return url;\n }\n const buffer = await response.arrayBuffer();\n if (cache !== null) await storeModel(cache, url, buffer);\n return new Uint8Array(buffer);\n } catch (err) {\n warnMetadataUnavailable(url, (err as Error).message);\n return url;\n }\n}\n\n/**\n * Put a model's bytes into the cache, never failing the load over it.\n *\n * Stores a fresh `Response` built from bytes already read rather than a\n * `clone()` of the network response: one read, and nothing that can throw\n * synchronously outside the guard. Awaited on purpose — a `put` left running\n * would keep its copy of the model reachable while ORT builds the session, the\n * same doubled peak {@link OrtSession.create} orders its reads to avoid.\n *\n * @param cache The open bucket.\n * @param url Cache key.\n * @param buffer The model.\n */\nasync function storeModel(cache: Cache, url: string, buffer: ArrayBuffer): Promise<void> {\n try {\n await cache.put(url, new Response(buffer));\n } catch {\n return;\n }\n}\n\n/**\n * Open a Cache Storage bucket, or report that there is none to open.\n *\n * Cache Storage only exists in secure contexts (HTTPS, `localhost`), and a\n * browser may refuse it outright — private windows, blocked site data, an\n * exhausted quota. None of that is worth failing a model load over: the model\n * is fetched from the network as if caching had not been asked for. A failed\n * `put` is swallowed for the same reason — see {@link storeModel}.\n *\n * @param name Bucket name.\n * @returns The cache, or `null` when this environment cannot provide one.\n */\nasync function openCache(name: string): Promise<Cache | null> {\n if (typeof caches === \"undefined\") return null;\n try {\n return await caches.open(name);\n } catch {\n return null;\n }\n}\n\n/**\n * Warn that a model's metadata could not be read, and say what that costs.\n *\n * The fallback itself is right — losing the metadata beats failing a load that\n * ORT could have completed on its own — but it used to be silent, and the\n * symptom it produces is remote from the cause: class names come back as\n * `class_0`, `class_1`, ... with nothing anywhere explaining why. Whoever hits\n * this needs to be told that passing `labels` is the way out.\n *\n * @param url The model URL that could not be fetched here.\n * @param reason What went wrong, as reported by `fetch`.\n */\nfunction warnMetadataUnavailable(url: string, reason: string): void {\n console.warn(\n `[@ort-vision-sdk/web] Could not fetch ${url} to read its metadata (${reason}). ` +\n \"Letting ONNX Runtime load it instead: the model will work, but its baked-in \" +\n \"class names are unavailable, so labels fall back to class_0, class_1, ... \" +\n \"Pass `labels` explicitly to name them.\",\n );\n}\n\nexport interface OrtSessionOptions {\n /**\n * Execution providers in preference order. `undefined` uses {@link DEFAULT_PROVIDERS}.\n *\n * Each entry is a name (`\"webgpu\"`, `\"wasm\"`) or ORT's config object for that\n * provider, which passes provider options through untouched —\n * `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`.\n *\n * Naming one explicitly also opts into a `console.warn` when this browser\n * cannot offer it, instead of falling back in silence.\n */\n readonly providers?: readonly ProviderSpec[];\n /**\n * Keep a URL model in the browser's Cache Storage between page loads.\n *\n * `true` uses the {@link DEFAULT_MODEL_CACHE} bucket; a string names the\n * bucket. A later `create` with the same URL reads the bytes from the cache\n * instead of the network — for a model of several megabytes, the bulk of\n * what a returning visitor waits for. Defaults to `false`.\n *\n * The URL is the cache key and nothing expires it: publish a changed model\n * under a new URL (`yolo.v2.onnx`, `?v=2`) or a new bucket name, or delete\n * the bucket with `caches.delete(name)`. Ignored for models passed as bytes,\n * and silently skipped where Cache Storage is unavailable (non-secure\n * contexts, blocked site data).\n */\n readonly cache?: boolean | string;\n /** Optional ORT session options forwarded to `InferenceSession.create`. */\n readonly sessionOptions?: ort.InferenceSession.SessionOptions;\n /**\n * Whether to read the model's custom metadata map (`names`, `task`, `imgsz`).\n * Defaults to `true`.\n *\n * The runtime does not expose that map, so it is read from the file itself —\n * which means a URL model is fetched here and handed to ORT as bytes instead\n * of letting ORT fetch it. That is the same single download either way, and\n * it is what lets a task resolve its labels off the model. Set to `false` to\n * keep the URL path untouched (unless {@link cache} is set, which needs the\n * bytes) and leave {@link OrtSession.metadata} empty.\n *\n * `false` is also the escape hatch when a device cannot afford the bytes: the\n * fetched buffer is dropped before ORT builds the graph (see\n * {@link OrtSession.create}), but ORT's own load path still keeps the model out\n * of reach of anything the SDK holds. A session built this way resolves its\n * input size from the graph as usual — only the class names are lost, so a\n * caller taking this route has to pass `labels` itself.\n */\n readonly readMetadata?: boolean;\n}\n\n/**\n * Warn when a provider named explicitly by the caller is not going to run.\n *\n * Only explicit requests are worth a warning. The default list exists precisely\n * so that falling from `webgpu` to `wasm` is the expected outcome — but a caller\n * who wrote `providers: [\"webgpu\"]` and lands on WASM has a page several times\n * slower than intended and nothing in the console to explain it.\n *\n * @param requested Providers that were asked for.\n * @param effective Providers that survived capability detection.\n */\nfunction warnOnDroppedProviders(requested: readonly string[], effective: readonly string[]): void {\n const dropped = requested.filter((provider) => !effective.includes(provider));\n if (dropped.length === 0) {\n return;\n }\n console.warn(\n `This browser cannot offer the requested execution provider(s) ${JSON.stringify(dropped)}; ` +\n `the session will run on ${JSON.stringify(effective)}. Inference still produces correct ` +\n \"results, on the fallback provider.\",\n );\n}\n\n/**\n * Name the tensor type of every graph input, straight from the model bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → tensor type name. Empty when the file carries no\n * readable graph, which callers read as \"assume float32\".\n */\nfunction declaredInputTypes(model: Uint8Array | ArrayBufferLike): Readonly<Record<string, string>> {\n const declared = readModelInputTypes(model);\n const named: Record<string, string> = {};\n for (const [name, elemType] of Object.entries(declared)) {\n named[name] = tensorTypeFor(elemType);\n }\n return named;\n}\n\n/**\n * Warn when the model's bytes were in hand but no input type came back.\n *\n * Every ONNX graph declares at least one input, so an empty result from bytes\n * means the reader failed, not that the model said nothing. Without this the\n * failure is invisible: the session falls back to float32, which is right for\n * most models and wrong for exactly the half-precision ones this reader exists\n * to support — so it looks like nothing is broken until a `predict()` throws\n * `Unexpected input data type`. That is how a 1 MB ceiling on the graph\n * descent shipped in 0.9.0 and reached a consumer.\n */\nfunction warnOnUnreadableTypes(): void {\n console.warn(\n \"Could not read any input type from this model's bytes; feeds will be built as float32. \" +\n \"A half-precision model will fail at inference with 'Unexpected input data type'. \" +\n \"Please report this with the model that produced it.\",\n );\n}\n\n/**\n * Refuse a half-precision model in an environment that cannot feed one.\n *\n * ORT requires a real `Float16Array` for a `float16` tensor — the same bits in\n * a `Uint16Array` are rejected — and not every browser has one yet. Without\n * this check the session builds happily and the first `predict()` throws from\n * inside the preprocessing, which is both later and further from the cause.\n *\n * @param inputTypes Tensor type per input name.\n * @throws {@link ModelLoadError} when the graph wants half precision and the\n * runtime has no `Float16Array`.\n */\nfunction assertFeedableTypes(inputTypes: Readonly<Record<string, string>>): void {\n const half = Object.entries(inputTypes).filter(([, type]) => type === \"float16\");\n if (half.length === 0 || hasFloat16Array()) return;\n const names = half.map(([name]) => name).join(\", \");\n throw new ModelLoadError(\n `This model declares half-precision input(s) [${names}], but this environment has no ` +\n \"Float16Array, which ONNX Runtime requires for a float16 tensor. Use a float32 export \" +\n \"of the model, or run in a browser that supports Float16Array.\",\n );\n}\n\n/**\n * Wrap an ONNX Runtime Web `InferenceSession` with convenient metadata access.\n *\n * The wrapper exposes input/output names and the shapes the graph declares,\n * manages execution-provider selection, provides a typed {@link OrtSession.run}\n * method, and releases the native session through {@link OrtSession.release}.\n */\nexport class OrtSession {\n private constructor(\n private readonly _session: ort.InferenceSession,\n /**\n * Execution providers this session is expected to run on.\n *\n * The requested list narrowed to what this browser can actually offer — a\n * `webgpu` entry survives only where an adapter exists. Best-effort: ORT-Web\n * exposes no way to ask which provider a session ended up on, so an entry\n * here means \"not ruled out\", not \"confirmed\". See\n * {@link requestedProviders} for what was asked for.\n *\n * When nothing survives — a caller asking for `webgpu` alone on a device\n * without it — this falls back to {@link FALLBACK_PROVIDER}, which ORT-Web\n * can always run. Handing ORT the unsatisfiable list instead makes\n * `InferenceSession.create` reject with \"no available backend found\", so the\n * page gets no inference at all rather than the slow-but-working fallback\n * the `console.warn` describes. Measured in a real Chromium, where\n * `navigator.gpu` exists but yields no adapter.\n */\n public readonly providers: readonly string[],\n private readonly _metadata: Readonly<Record<string, string>>,\n /**\n * Execution providers that were asked for, after defaults were applied.\n *\n * Kept separate because ORT-Web falls back silently: a page that asks for\n * `webgpu` on a device without it runs on WASM and is told nothing.\n */\n public readonly requestedProviders: readonly string[],\n /**\n * Tensor type each input declares, keyed by input name.\n *\n * Read from the model file, not from the session: `inputMetadata` is\n * `undefined` on `onnxruntime-web` 1.20.1. Empty when the bytes were never\n * in hand — a URL loaded with `readMetadata: false` — in which case every\n * feed is built as float32, the behaviour before this existed.\n */\n private readonly _inputTypes: Readonly<Record<string, string>> = {},\n ) {}\n\n /**\n * Tail of the run queue: settles when the latest queued run has finished.\n *\n * See {@link run} for why runs are serialized.\n */\n private _runQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Load an ONNX model into an ORT inference session.\n *\n * The metadata map is read **before** the session is built, and that order is\n * load-bearing on memory-constrained devices. ORT copies the model into its\n * WASM heap and then allocates the graph and the weights on top of that copy;\n * a `readModelMetadata` call placed after `InferenceSession.create` keeps the\n * JavaScript-side buffer reachable across the whole build, so a 5 MB model\n * costs 5 MB of JS heap plus 5 MB of WASM heap plus the weights at the same\n * instant. Reading first makes the buffer collectable as soon as ORT has copied\n * it — on a phone that was the difference between a session and\n * `Can't create a session. failed to allocate a buffer of size N`.\n *\n * The provider probe and the model download run concurrently: neither\n * depends on the other, and on a real GPU `requestAdapter()` is not free.\n * When the model is downloaded here, ORT's runtime is started alongside the\n * download too — see {@link warmRuntime}.\n *\n * A model whose metadata carries {@link GRAPH_OPTIMIZATION_KEY} was already\n * optimized offline by the Python SDK's `optimize_model`, so it is loaded\n * with `graphOptimizationLevel: \"disabled\"` instead of paying the optimizer a\n * second time — measured on a YOLO11n-seg under WASM, 29 ms of session\n * creation down to 12 ms with unchanged inference time. An explicit\n * `graphOptimizationLevel` in `sessionOptions` always wins. The mark is read\n * with the rest of the metadata, so `readMetadata: false` skips it too.\n *\n * @param model Either a URL string, or a `Uint8Array`/`ArrayBuffer` containing the model bytes.\n * @param options Provider list, pass-through `SessionOptions`, and whether to\n * read the model's metadata map (see {@link OrtSessionOptions.readMetadata}).\n * @throws {@link ModelLoadError} if the model cannot be loaded.\n */\n static async create(model: ModelSource, options: OrtSessionOptions = {}): Promise<OrtSession> {\n const requested = resolveProviders(options.providers);\n const wantsMetadata = options.readMetadata !== false;\n const cacheName =\n options.cache === true ? DEFAULT_MODEL_CACHE : options.cache ? options.cache : null;\n const shouldFetch = typeof model === \"string\" && (wantsMetadata || cacheName !== null);\n const detection = detectProviders(requested).then((detected) =>\n detected.length > 0 ? detected : [FALLBACK_PROVIDER],\n );\n const [detected, source] = await Promise.all([\n detection,\n shouldFetch ? fetchModel(model, cacheName) : Promise.resolve(model),\n shouldFetch ? detection.then(warmRuntime) : Promise.resolve(),\n ]);\n const metadata =\n wantsMetadata && typeof source !== \"string\" ? readModelMetadata(source) : {};\n const specs = keepQuantizedOffWebGpu(detected, metadata);\n const requestedNames = requested.map(providerName);\n const providers = specs.map(providerName);\n if (options.providers !== undefined && options.providers.length > 0) {\n warnOnDroppedProviders(requestedNames, detected.map(providerName));\n }\n if (metadata[GRAPH_OPTIMIZATION_KEY] !== undefined && providers.includes(\"webgpu\")) {\n warnPreOptimizedOnWebGpu();\n }\n const preOptimized =\n metadata[GRAPH_OPTIMIZATION_KEY] !== undefined &&\n options.sessionOptions?.graphOptimizationLevel === undefined;\n const sessionOptions: ort.InferenceSession.SessionOptions = {\n ...(preOptimized ? { graphOptimizationLevel: \"disabled\" as const } : {}),\n ...(options.sessionOptions ?? {}),\n executionProviders: specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n };\n const inputTypes = typeof source !== \"string\" ? declaredInputTypes(source) : {};\n if (typeof source !== \"string\" && Object.keys(inputTypes).length === 0) {\n warnOnUnreadableTypes();\n }\n assertFeedableTypes(inputTypes);\n\n let session: ort.InferenceSession;\n try {\n if (typeof source === \"string\") {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else if (source instanceof Uint8Array) {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else {\n session = await ortRuntime.InferenceSession.create(\n source as ArrayBuffer,\n sessionOptions,\n );\n }\n } catch (err) {\n throw new ModelLoadError(`Failed to load ONNX model: ${(err as Error).message}`, {\n cause: err,\n });\n }\n\n return new OrtSession(session, providers, metadata, requestedNames, inputTypes);\n }\n\n /**\n * Tensor type each input declares, in declaration order.\n *\n * `\"float32\"` for a normal export, `\"float16\"` for one exported with\n * `half=True`. ORT matches a feed's type against this exactly, so the tasks\n * read it and convert at the feed boundary.\n */\n get inputDtypes(): readonly string[] {\n return this.inputNames.map((name) => this._inputTypes[name] ?? DEFAULT_TENSOR_TYPE);\n }\n\n /** Tensor type the first input declares. */\n get inputDtype(): string {\n return this._inputTypes[this.inputName] ?? DEFAULT_TENSOR_TYPE;\n }\n\n /** Names of the model's inputs, in declaration order. */\n get inputNames(): readonly string[] {\n return this._session.inputNames;\n }\n\n /** Name of the first (and usually only) input. */\n get inputName(): string {\n const name = this._session.inputNames[0];\n if (name === undefined) {\n throw new InferenceError(\"Model has no inputs.\");\n }\n return name;\n }\n\n /** Names of the model's outputs, in declaration order. */\n get outputNames(): readonly string[] {\n return this._session.outputNames;\n }\n\n /**\n * Shapes the graph declares for its inputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Empty shapes mean the runtime\n * reported no metadata — either a non-tensor input, or an `onnxruntime-web`\n * older than 1.21, which predates input metadata.\n */\n get inputShapes(): readonly DeclaredShape[] {\n return declaredShapesFrom(\n this._session.inputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n );\n }\n\n /**\n * Shape the graph declares for its first input, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get inputShape(): DeclaredShape {\n return this.inputShapes[0] ?? [];\n }\n\n /**\n * Shapes the graph declares for its outputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Reading them is how a task can\n * tell how many classes a head emits without being told.\n */\n get outputShapes(): readonly DeclaredShape[] {\n return declaredShapesFrom(\n this._session.outputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n );\n }\n\n /**\n * Shape the graph declares for its first output, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get outputShape(): DeclaredShape {\n return this.outputShapes[0] ?? [];\n }\n\n /**\n * The model's custom metadata map — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export.\n *\n * Read from the model's bytes at load time, since the runtime does not expose\n * it. Empty when the session was created with `readMetadata: false`, from a\n * URL that could not be fetched here, or from a model carrying no metadata.\n */\n get metadata(): Readonly<Record<string, string>> {\n return this._metadata;\n }\n\n /**\n * Release the native session and free its memory.\n *\n * Call it when a session is discarded while the page lives on — rebuilding a\n * task at a different input size, swapping in a newer model. A failure from\n * the runtime is ignored: a session being torn down has nothing left to fail\n * at, and the caller is already moving on.\n */\n async release(): Promise<void> {\n await this._session.release().catch(() => undefined);\n }\n\n /** The underlying `onnxruntime-web` session, for advanced use cases. */\n get raw(): ort.InferenceSession {\n return this._session;\n }\n\n /**\n * Run inference and return all outputs.\n *\n * Runs on one session are serialized. ONNX Runtime Web refuses a second\n * `run` while one is in flight — it rejects with `Session already started` —\n * so two overlapping `predict()` calls on the same task used to fail. Queued\n * here, they overlap where they can: while one run executes (in a worker,\n * with `env.wasm.proxy`, or on the GPU), the next `predict()` decodes and\n * preprocesses its frame and only waits for its turn at the runtime. A run\n * that fails does not block the ones behind it.\n *\n * @param feeds Map of input name to `ort.Tensor`. Keys must match {@link inputNames}.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n run(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n const turn = this._runQueue.then(() => this._runNow(feeds));\n this._runQueue = turn.catch(() => undefined);\n return turn;\n }\n\n /**\n * Execute one run immediately; only {@link run}'s queue calls this.\n *\n * @param feeds Map of input name to `ort.Tensor`.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n private async _runNow(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n try {\n const result = await this._session.run(this._asDeclaredTypes(feeds));\n return result as Record<string, ort.Tensor>;\n } catch (err) {\n throw new InferenceError(`Inference failed: ${(err as Error).message}`, { cause: err });\n }\n }\n\n /**\n * Rebuild any feed whose type does not match what its input declares.\n *\n * ORT matches feed types against the graph exactly: a float32 tensor against\n * a `half=True` export fails the run with `Unexpected input data type`. Every\n * preprocessing path in this SDK produces `Float32Array`, on purpose — the\n * normalization arithmetic belongs in single precision — so the conversion\n * happens here, once, at the only boundary all of them pass through. A feed\n * that already carries the declared type is handed on untouched, so a caller\n * building its own half tensor pays nothing.\n *\n * @param feeds The tensors to run with.\n * @returns The same mapping, with mismatched float32 feeds converted.\n */\n private _asDeclaredTypes(feeds: Record<string, ort.Tensor>): Record<string, ort.Tensor> {\n let converted: Record<string, ort.Tensor> | null = null;\n for (const [name, tensor] of Object.entries(feeds)) {\n const declared = this._inputTypes[name];\n if (declared === undefined || declared === tensor.type) continue;\n if (!(tensor.data instanceof Float32Array)) continue;\n const data = toFeedData(tensor.data, declared);\n if (data === tensor.data) continue;\n converted ??= { ...feeds };\n converted[name] = new ortRuntime.Tensor(\n declared as \"float16\",\n data as unknown as Float32Array,\n tensor.dims as number[],\n );\n }\n return converted ?? feeds;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.js","names":[],"sources":["../../../src/vision/core/session.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Thin wrapper around `onnxruntime-web` `InferenceSession` with typed metadata.\n */\n\nimport type * as ort from \"onnxruntime-web\";\nimport * as ortRuntime from \"onnxruntime-web\";\n\nimport { DEFAULT_TENSOR_TYPE, hasFloat16Array, tensorTypeFor, toFeedData } from \"./dtypes\";\nimport { InferenceError, ModelLoadError } from \"./exceptions\";\nimport { type DeclaredShape, declaredShapesFrom } from \"./graph\";\nimport { readModelInputTypes, readModelMetadata, readModelShapes } from \"./metadata\";\nimport {\n FALLBACK_PROVIDER,\n type ProviderSpec,\n detectProviders,\n providerName,\n resolveProviders,\n} from \"./providers\";\n\n/** Anything `InferenceSession.create` accepts. */\nexport type ModelSource = string | ArrayBufferLike | Uint8Array;\n\n/**\n * Metadata key naming the level a model was graph-optimized at offline.\n *\n * Written by the Python SDK's `optimize_model`; both test suites pin the same\n * string, so a rename on one side fails. See {@link OrtSession.create} for what\n * the session does when it finds it.\n */\nexport const GRAPH_OPTIMIZATION_KEY = \"ort_vision_sdk.graph_optimization\";\n\n/**\n * An 84-byte ONNX model — one `Identity` on a float `[1]` — used to start the runtime.\n *\n * Generated with `onnx.helper` (opset 13, IR 7, producer `ort-vision-sdk`).\n * See {@link warmRuntime} for why it exists.\n */\nconst RUNTIME_PROBE_MODEL =\n \"CAcSDm9ydC12aXNpb24tc2RrOjoKEAoBeBIBeSIISWRlbnRpdHkSBHdhcm1aDwoBeBIKCggIARIECgIIAWIPCgF5EgoKCAgBEgQKAggBQgQKABAN\";\n\n/** Runtime start-ups already begun on this page, keyed by provider names. */\nconst runtimeWarmups = new Map<string, Promise<void>>();\n\n/**\n * Start ONNX Runtime's backends for a provider list, once per page.\n *\n * ORT downloads and compiles its WebAssembly binary — 12.8 MB for the plain\n * WASM build, 25.9 MB for the one carrying WebGPU — inside the first\n * `InferenceSession.create`. {@link OrtSession.create} only reaches that call\n * after it has downloaded the model, so on a real network the two largest\n * downloads of a page load ran one after the other. Creating and releasing a\n * session on a tiny model while the real one downloads lets them overlap; the\n * real `create` then finds the runtime ready.\n *\n * A failure here is swallowed: the real `create` runs against the same runtime\n * and reports the same problem with the right model in the message.\n *\n * @param specs Providers the real session will use.\n * @returns Settles when the runtime is up, or when starting it failed.\n */\nfunction warmRuntime(specs: readonly ProviderSpec[]): Promise<void> {\n const key = specs.map(providerName).join(\",\");\n let pending = runtimeWarmups.get(key);\n if (pending === undefined) {\n pending = (async () => {\n try {\n const probe = Uint8Array.from(atob(RUNTIME_PROBE_MODEL), (c) => c.charCodeAt(0));\n const session = await ortRuntime.InferenceSession.create(probe, {\n executionProviders:\n specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n });\n await session.release();\n } catch {\n return;\n }\n })();\n runtimeWarmups.set(key, pending);\n }\n return pending;\n}\n\n/**\n * Warn that a model optimized offline is about to run on WebGPU.\n *\n * `optimize_model` fuses operators for the CPU, which is what the WASM backend\n * runs. On WebGPU some of those fused nodes have no GPU kernel: on a\n * YOLO11n-seg, ONNX Runtime placed 2 nodes on the CPU for the optimized file\n * and none for the original, so every inference pays GPU↔CPU copies. The SDK\n * cannot swap the file, so it says which one to ship.\n */\nfunction warnPreOptimizedOnWebGpu(): void {\n console.warn(\n \"[@ort-vision-sdk/web] This model was pre-optimized by optimize_model, which targets the \" +\n \"WASM backend; on WebGPU some of its fused nodes fall back to the CPU. For WebGPU, ship \" +\n \"the original export instead.\",\n );\n}\n\n/**\n * Metadata key the Python SDK's `quantize_model` writes on an INT8 model.\n *\n * Mirrored by `QUANTIZATION_KEY` in the Python SDK; both test suites pin the\n * string. See {@link keepQuantizedOffWebGpu} for what a session does with it.\n */\nexport const QUANTIZATION_KEY = \"ort_vision_sdk.quantization\";\n\n/**\n * Drop `webgpu` from the providers of a model `quantize_model` produced.\n *\n * ONNX Runtime Web's WebGPU `DequantizeLinear` rejects the quantized bias such\n * a model carries — `scale and zero-point inputs must have the same rank` —\n * so the first `predict()` fails; and a variant with the bias left in float\n * ran but returned different detections than WASM for the same file. The\n * model is fine on WASM, which is also where INT8 pays (52.7 ms vs 68.4 ms on\n * a YOLO11n-seg), so the session runs there and says so.\n *\n * @param specs Providers that survived detection.\n * @param metadata The model's metadata map.\n * @returns `specs` without `webgpu` when the model is marked quantized; the\n * WASM fallback when nothing else is left.\n */\nfunction keepQuantizedOffWebGpu(\n specs: readonly ProviderSpec[],\n metadata: Readonly<Record<string, string>>,\n): ProviderSpec[] {\n if (metadata[QUANTIZATION_KEY] === undefined) return [...specs];\n const kept = specs.filter((spec) => providerName(spec) !== \"webgpu\");\n if (kept.length === specs.length) return kept;\n console.warn(\n `[@ort-vision-sdk/web] This model was quantized by quantize_model (${metadata[QUANTIZATION_KEY]}); ` +\n \"ONNX Runtime Web's WebGPU backend cannot run its quantized operators, so it runs on WASM.\",\n );\n return kept.length > 0 ? kept : [FALLBACK_PROVIDER];\n}\n\n/** Cache Storage bucket used when {@link OrtSessionOptions.cache} is `true`. */\nexport const DEFAULT_MODEL_CACHE = \"ort-vision-sdk-models\";\n\n/**\n * Fetch a model URL as bytes so its metadata can be read.\n *\n * Falls back to the URL itself when the fetch fails, letting ORT try its own\n * load path: losing the metadata map is a downgrade, but failing to load a model\n * that ORT could have fetched would be a regression.\n *\n * @param url Where the `.onnx` lives.\n * @param cacheName Cache Storage bucket to read from and fill, or `null` to\n * always go to the network.\n * @returns The model bytes, or the original URL when they could not be fetched.\n */\nasync function fetchModel(url: string, cacheName: string | null): Promise<Uint8Array | string> {\n const cache = cacheName === null ? null : await openCache(cacheName);\n if (cache !== null) {\n const hit = await cache.match(url).catch(() => undefined);\n if (hit !== undefined) return new Uint8Array(await hit.arrayBuffer());\n }\n try {\n const response = await fetch(url);\n if (!response.ok) {\n warnMetadataUnavailable(url, `HTTP ${response.status} ${response.statusText}`);\n return url;\n }\n const buffer = await response.arrayBuffer();\n if (cache !== null) await storeModel(cache, url, buffer);\n return new Uint8Array(buffer);\n } catch (err) {\n warnMetadataUnavailable(url, (err as Error).message);\n return url;\n }\n}\n\n/**\n * Put a model's bytes into the cache, never failing the load over it.\n *\n * Stores a fresh `Response` built from bytes already read rather than a\n * `clone()` of the network response: one read, and nothing that can throw\n * synchronously outside the guard. Awaited on purpose — a `put` left running\n * would keep its copy of the model reachable while ORT builds the session, the\n * same doubled peak {@link OrtSession.create} orders its reads to avoid.\n *\n * @param cache The open bucket.\n * @param url Cache key.\n * @param buffer The model.\n */\nasync function storeModel(cache: Cache, url: string, buffer: ArrayBuffer): Promise<void> {\n try {\n await cache.put(url, new Response(buffer));\n } catch {\n return;\n }\n}\n\n/**\n * Open a Cache Storage bucket, or report that there is none to open.\n *\n * Cache Storage only exists in secure contexts (HTTPS, `localhost`), and a\n * browser may refuse it outright — private windows, blocked site data, an\n * exhausted quota. None of that is worth failing a model load over: the model\n * is fetched from the network as if caching had not been asked for. A failed\n * `put` is swallowed for the same reason — see {@link storeModel}.\n *\n * @param name Bucket name.\n * @returns The cache, or `null` when this environment cannot provide one.\n */\nasync function openCache(name: string): Promise<Cache | null> {\n if (typeof caches === \"undefined\") return null;\n try {\n return await caches.open(name);\n } catch {\n return null;\n }\n}\n\n/**\n * Warn that a model's metadata could not be read, and say what that costs.\n *\n * The fallback itself is right — losing the metadata beats failing a load that\n * ORT could have completed on its own — but it used to be silent, and the\n * symptom it produces is remote from the cause: class names come back as\n * `class_0`, `class_1`, ... with nothing anywhere explaining why. Whoever hits\n * this needs to be told that passing `labels` is the way out.\n *\n * @param url The model URL that could not be fetched here.\n * @param reason What went wrong, as reported by `fetch`.\n */\nfunction warnMetadataUnavailable(url: string, reason: string): void {\n console.warn(\n `[@ort-vision-sdk/web] Could not fetch ${url} to read its metadata (${reason}). ` +\n \"Letting ONNX Runtime load it instead: the model will work, but its baked-in \" +\n \"class names are unavailable, so labels fall back to class_0, class_1, ... \" +\n \"Pass `labels` explicitly to name them.\",\n );\n}\n\nexport interface OrtSessionOptions {\n /**\n * Execution providers in preference order. `undefined` uses {@link DEFAULT_PROVIDERS}.\n *\n * Each entry is a name (`\"webgpu\"`, `\"wasm\"`) or ORT's config object for that\n * provider, which passes provider options through untouched —\n * `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`.\n *\n * Naming one explicitly also opts into a `console.warn` when this browser\n * cannot offer it, instead of falling back in silence.\n */\n readonly providers?: readonly ProviderSpec[];\n /**\n * Keep a URL model in the browser's Cache Storage between page loads.\n *\n * `true` uses the {@link DEFAULT_MODEL_CACHE} bucket; a string names the\n * bucket. A later `create` with the same URL reads the bytes from the cache\n * instead of the network — for a model of several megabytes, the bulk of\n * what a returning visitor waits for. Defaults to `false`.\n *\n * The URL is the cache key and nothing expires it: publish a changed model\n * under a new URL (`yolo.v2.onnx`, `?v=2`) or a new bucket name, or delete\n * the bucket with `caches.delete(name)`. Ignored for models passed as bytes,\n * and silently skipped where Cache Storage is unavailable (non-secure\n * contexts, blocked site data).\n */\n readonly cache?: boolean | string;\n /** Optional ORT session options forwarded to `InferenceSession.create`. */\n readonly sessionOptions?: ort.InferenceSession.SessionOptions;\n /**\n * Whether to read the model's custom metadata map (`names`, `task`, `imgsz`).\n * Defaults to `true`.\n *\n * The runtime does not expose that map, so it is read from the file itself —\n * which means a URL model is fetched here and handed to ORT as bytes instead\n * of letting ORT fetch it. That is the same single download either way, and\n * it is what lets a task resolve its labels off the model. Set to `false` to\n * keep the URL path untouched (unless {@link cache} is set, which needs the\n * bytes) and leave {@link OrtSession.metadata} empty.\n *\n * `false` is also the escape hatch when a device cannot afford the bytes: the\n * fetched buffer is dropped before ORT builds the graph (see\n * {@link OrtSession.create}), but ORT's own load path still keeps the model out\n * of reach of anything the SDK holds. A session built this way resolves its\n * input size from the graph as usual — only the class names are lost, so a\n * caller taking this route has to pass `labels` itself.\n */\n readonly readMetadata?: boolean;\n}\n\n/**\n * Warn when a provider named explicitly by the caller is not going to run.\n *\n * Only explicit requests are worth a warning. The default list exists precisely\n * so that falling from `webgpu` to `wasm` is the expected outcome — but a caller\n * who wrote `providers: [\"webgpu\"]` and lands on WASM has a page several times\n * slower than intended and nothing in the console to explain it.\n *\n * @param requested Providers that were asked for.\n * @param effective Providers that survived capability detection.\n */\nfunction warnOnDroppedProviders(requested: readonly string[], effective: readonly string[]): void {\n const dropped = requested.filter((provider) => !effective.includes(provider));\n if (dropped.length === 0) {\n return;\n }\n console.warn(\n `This browser cannot offer the requested execution provider(s) ${JSON.stringify(dropped)}; ` +\n `the session will run on ${JSON.stringify(effective)}. Inference still produces correct ` +\n \"results, on the fallback provider.\",\n );\n}\n\n/**\n * Name the tensor type of every graph input, straight from the model bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → tensor type name. Empty when the file carries no\n * readable graph, which callers read as \"assume float32\".\n */\nfunction declaredInputTypes(model: Uint8Array | ArrayBufferLike): Readonly<Record<string, string>> {\n const declared = readModelInputTypes(model);\n const named: Record<string, string> = {};\n for (const [name, elemType] of Object.entries(declared)) {\n named[name] = tensorTypeFor(elemType);\n }\n return named;\n}\n\n/**\n * Warn when the model's bytes were in hand but no input type came back.\n *\n * Every ONNX graph declares at least one input, so an empty result from bytes\n * means the reader failed, not that the model said nothing. Without this the\n * failure is invisible: the session falls back to float32, which is right for\n * most models and wrong for exactly the half-precision ones this reader exists\n * to support — so it looks like nothing is broken until a `predict()` throws\n * `Unexpected input data type`. That is how a 1 MB ceiling on the graph\n * descent shipped in 0.9.0 and reached a consumer.\n */\nfunction warnOnUnreadableTypes(): void {\n console.warn(\n \"Could not read any input type from this model's bytes; feeds will be built as float32. \" +\n \"A half-precision model will fail at inference with 'Unexpected input data type'. \" +\n \"Please report this with the model that produced it.\",\n );\n}\n\n/**\n * Refuse a half-precision model in an environment that cannot feed one.\n *\n * ORT requires a real `Float16Array` for a `float16` tensor — the same bits in\n * a `Uint16Array` are rejected — and not every browser has one yet. Without\n * this check the session builds happily and the first `predict()` throws from\n * inside the preprocessing, which is both later and further from the cause.\n *\n * @param inputTypes Tensor type per input name.\n * @throws {@link ModelLoadError} when the graph wants half precision and the\n * runtime has no `Float16Array`.\n */\nfunction assertFeedableTypes(inputTypes: Readonly<Record<string, string>>): void {\n const half = Object.entries(inputTypes).filter(([, type]) => type === \"float16\");\n if (half.length === 0 || hasFloat16Array()) return;\n const names = half.map(([name]) => name).join(\", \");\n throw new ModelLoadError(\n `This model declares half-precision input(s) [${names}], but this environment has no ` +\n \"Float16Array, which ONNX Runtime requires for a float16 tensor. Use a float32 export \" +\n \"of the model, or run in a browser that supports Float16Array.\",\n );\n}\n\n/**\n * Wrap an ONNX Runtime Web `InferenceSession` with convenient metadata access.\n *\n * The wrapper exposes input/output names and the shapes the graph declares,\n * manages execution-provider selection, provides a typed {@link OrtSession.run}\n * method, and releases the native session through {@link OrtSession.release}.\n */\nexport class OrtSession {\n private constructor(\n private readonly _session: ort.InferenceSession,\n /**\n * Execution providers this session is expected to run on.\n *\n * The requested list narrowed to what this browser can actually offer — a\n * `webgpu` entry survives only where an adapter exists. Best-effort: ORT-Web\n * exposes no way to ask which provider a session ended up on, so an entry\n * here means \"not ruled out\", not \"confirmed\". See\n * {@link requestedProviders} for what was asked for.\n *\n * When nothing survives — a caller asking for `webgpu` alone on a device\n * without it — this falls back to {@link FALLBACK_PROVIDER}, which ORT-Web\n * can always run. Handing ORT the unsatisfiable list instead makes\n * `InferenceSession.create` reject with \"no available backend found\", so the\n * page gets no inference at all rather than the slow-but-working fallback\n * the `console.warn` describes. Measured in a real Chromium, where\n * `navigator.gpu` exists but yields no adapter.\n */\n public readonly providers: readonly string[],\n private readonly _metadata: Readonly<Record<string, string>>,\n /**\n * Execution providers that were asked for, after defaults were applied.\n *\n * Kept separate because ORT-Web falls back silently: a page that asks for\n * `webgpu` on a device without it runs on WASM and is told nothing.\n */\n public readonly requestedProviders: readonly string[],\n /**\n * Tensor type each input declares, keyed by input name.\n *\n * Read from the model file, not from the session: `inputMetadata` is\n * `undefined` on `onnxruntime-web` 1.20.1. Empty when the bytes were never\n * in hand — a URL loaded with `readMetadata: false` — in which case every\n * feed is built as float32, the behaviour before this existed.\n */\n private readonly _inputTypes: Readonly<Record<string, string>> = {},\n /**\n * Shapes the model file declares, keyed by value name.\n *\n * The fallback for {@link inputShapes} and {@link outputShapes} when the\n * runtime reports none, which `onnxruntime-web` does below 1.22. Empty when\n * the bytes were never in hand (a URL loaded with `readMetadata: false`).\n */\n private readonly _fileShapes: {\n readonly inputs: Readonly<Record<string, DeclaredShape>>;\n readonly outputs: Readonly<Record<string, DeclaredShape>>;\n } = { inputs: {}, outputs: {} },\n ) {}\n\n /**\n * Tail of the run queue: settles when the latest queued run has finished.\n *\n * See {@link run} for why runs are serialized.\n */\n private _runQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Load an ONNX model into an ORT inference session.\n *\n * The metadata map is read **before** the session is built, and that order is\n * load-bearing on memory-constrained devices. ORT copies the model into its\n * WASM heap and then allocates the graph and the weights on top of that copy;\n * a `readModelMetadata` call placed after `InferenceSession.create` keeps the\n * JavaScript-side buffer reachable across the whole build, so a 5 MB model\n * costs 5 MB of JS heap plus 5 MB of WASM heap plus the weights at the same\n * instant. Reading first makes the buffer collectable as soon as ORT has copied\n * it — on a phone that was the difference between a session and\n * `Can't create a session. failed to allocate a buffer of size N`.\n *\n * The provider probe and the model download run concurrently: neither\n * depends on the other, and on a real GPU `requestAdapter()` is not free.\n * When the model is downloaded here, ORT's runtime is started alongside the\n * download too — see {@link warmRuntime}.\n *\n * A model whose metadata carries {@link GRAPH_OPTIMIZATION_KEY} was already\n * optimized offline by the Python SDK's `optimize_model`, so it is loaded\n * with `graphOptimizationLevel: \"disabled\"` instead of paying the optimizer a\n * second time — measured on a YOLO11n-seg under WASM, 29 ms of session\n * creation down to 12 ms with unchanged inference time. An explicit\n * `graphOptimizationLevel` in `sessionOptions` always wins. The mark is read\n * with the rest of the metadata, so `readMetadata: false` skips it too.\n *\n * @param model Either a URL string, or a `Uint8Array`/`ArrayBuffer` containing the model bytes.\n * @param options Provider list, pass-through `SessionOptions`, and whether to\n * read the model's metadata map (see {@link OrtSessionOptions.readMetadata}).\n * @throws {@link ModelLoadError} if the model cannot be loaded.\n */\n static async create(model: ModelSource, options: OrtSessionOptions = {}): Promise<OrtSession> {\n const requested = resolveProviders(options.providers);\n const wantsMetadata = options.readMetadata !== false;\n const cacheName =\n options.cache === true ? DEFAULT_MODEL_CACHE : options.cache ? options.cache : null;\n const shouldFetch = typeof model === \"string\" && (wantsMetadata || cacheName !== null);\n const detection = detectProviders(requested).then((detected) =>\n detected.length > 0 ? detected : [FALLBACK_PROVIDER],\n );\n const [detected, source] = await Promise.all([\n detection,\n shouldFetch ? fetchModel(model, cacheName) : Promise.resolve(model),\n shouldFetch ? detection.then(warmRuntime) : Promise.resolve(),\n ]);\n const metadata =\n wantsMetadata && typeof source !== \"string\" ? readModelMetadata(source) : {};\n const specs = keepQuantizedOffWebGpu(detected, metadata);\n const requestedNames = requested.map(providerName);\n const providers = specs.map(providerName);\n if (options.providers !== undefined && options.providers.length > 0) {\n warnOnDroppedProviders(requestedNames, detected.map(providerName));\n }\n if (metadata[GRAPH_OPTIMIZATION_KEY] !== undefined && providers.includes(\"webgpu\")) {\n warnPreOptimizedOnWebGpu();\n }\n const preOptimized =\n metadata[GRAPH_OPTIMIZATION_KEY] !== undefined &&\n options.sessionOptions?.graphOptimizationLevel === undefined;\n const sessionOptions: ort.InferenceSession.SessionOptions = {\n ...(preOptimized ? { graphOptimizationLevel: \"disabled\" as const } : {}),\n ...(options.sessionOptions ?? {}),\n executionProviders: specs as ort.InferenceSession.SessionOptions[\"executionProviders\"],\n };\n const inputTypes = typeof source !== \"string\" ? declaredInputTypes(source) : {};\n const fileShapes =\n typeof source !== \"string\" ? readModelShapes(source) : { inputs: {}, outputs: {} };\n if (typeof source !== \"string\" && Object.keys(inputTypes).length === 0) {\n warnOnUnreadableTypes();\n }\n assertFeedableTypes(inputTypes);\n\n let session: ort.InferenceSession;\n try {\n if (typeof source === \"string\") {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else if (source instanceof Uint8Array) {\n session = await ortRuntime.InferenceSession.create(source, sessionOptions);\n } else {\n session = await ortRuntime.InferenceSession.create(\n source as ArrayBuffer,\n sessionOptions,\n );\n }\n } catch (err) {\n throw new ModelLoadError(`Failed to load ONNX model: ${(err as Error).message}`, {\n cause: err,\n });\n }\n\n return new OrtSession(session, providers, metadata, requestedNames, inputTypes, fileShapes);\n }\n\n /**\n * Tensor type each input declares, in declaration order.\n *\n * `\"float32\"` for a normal export, `\"float16\"` for one exported with\n * `half=True`. ORT matches a feed's type against this exactly, so the tasks\n * read it and convert at the feed boundary.\n */\n get inputDtypes(): readonly string[] {\n return this.inputNames.map((name) => this._inputTypes[name] ?? DEFAULT_TENSOR_TYPE);\n }\n\n /** Tensor type the first input declares. */\n get inputDtype(): string {\n return this._inputTypes[this.inputName] ?? DEFAULT_TENSOR_TYPE;\n }\n\n /** Names of the model's inputs, in declaration order. */\n get inputNames(): readonly string[] {\n return this._session.inputNames;\n }\n\n /** Name of the first (and usually only) input. */\n get inputName(): string {\n const name = this._session.inputNames[0];\n if (name === undefined) {\n throw new InferenceError(\"Model has no inputs.\");\n }\n return name;\n }\n\n /** Names of the model's outputs, in declaration order. */\n get outputNames(): readonly string[] {\n return this._session.outputNames;\n }\n\n /**\n * Shapes the graph declares for its inputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Read from the runtime when it\n * reports them (`onnxruntime-web` >= 1.22), otherwise from the model file. An\n * empty shape means neither source declared one: a non-tensor input, or a URL\n * model loaded with `readMetadata: false` on a runtime that reports nothing.\n */\n get inputShapes(): readonly DeclaredShape[] {\n return this._shapesOf(\n this._session.inputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n this._session.inputNames,\n this._fileShapes.inputs,\n );\n }\n\n /**\n * Shape the graph declares for its first input, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get inputShape(): DeclaredShape {\n return this.inputShapes[0] ?? [];\n }\n\n /**\n * Shapes the graph declares for its outputs, in declaration order.\n *\n * Dynamic (symbolic) axes appear as `null`. Reading them is how a task can\n * tell how many classes a head emits without being told. Same sources as\n * {@link inputShapes}.\n */\n get outputShapes(): readonly DeclaredShape[] {\n return this._shapesOf(\n this._session.outputMetadata as\n readonly ort.InferenceSession.ValueMetadata[] | undefined,\n this._session.outputNames,\n this._fileShapes.outputs,\n );\n }\n\n /**\n * Pick the runtime's declared shapes, or the file's when the runtime has none.\n *\n * @param metadata What the runtime reports, `undefined` below 1.22.\n * @param names The session's value names, in its own order.\n * @param fromFile Shapes the model file declares, keyed by name.\n * @returns One shape per name, in the session's order.\n */\n private _shapesOf(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n names: readonly string[],\n fromFile: Readonly<Record<string, DeclaredShape>>,\n ): readonly DeclaredShape[] {\n const reported = declaredShapesFrom(metadata);\n if (reported.length > 0) return reported;\n return names.map((name) => fromFile[name] ?? []);\n }\n\n /**\n * Shape the graph declares for its first output, dynamic axes as `null`.\n *\n * Empty when the runtime reports no metadata for it.\n */\n get outputShape(): DeclaredShape {\n return this.outputShapes[0] ?? [];\n }\n\n /**\n * The model's custom metadata map — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export.\n *\n * Read from the model's bytes at load time, since the runtime does not expose\n * it. Empty when the session was created with `readMetadata: false`, from a\n * URL that could not be fetched here, or from a model carrying no metadata.\n */\n get metadata(): Readonly<Record<string, string>> {\n return this._metadata;\n }\n\n /**\n * Release the native session and free its memory.\n *\n * Call it when a session is discarded while the page lives on — rebuilding a\n * task at a different input size, swapping in a newer model. A failure from\n * the runtime is ignored: a session being torn down has nothing left to fail\n * at, and the caller is already moving on.\n */\n async release(): Promise<void> {\n await this._session.release().catch(() => undefined);\n }\n\n /** The underlying `onnxruntime-web` session, for advanced use cases. */\n get raw(): ort.InferenceSession {\n return this._session;\n }\n\n /**\n * Run inference and return all outputs.\n *\n * Runs on one session are serialized. ONNX Runtime Web refuses a second\n * `run` while one is in flight — it rejects with `Session already started` —\n * so two overlapping `predict()` calls on the same task used to fail. Queued\n * here, they overlap where they can: while one run executes (in a worker,\n * with `env.wasm.proxy`, or on the GPU), the next `predict()` decodes and\n * preprocesses its frame and only waits for its turn at the runtime. A run\n * that fails does not block the ones behind it.\n *\n * @param feeds Map of input name to `ort.Tensor`. Keys must match {@link inputNames}.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n run(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n const turn = this._runQueue.then(() => this._runNow(feeds));\n this._runQueue = turn.catch(() => undefined);\n return turn;\n }\n\n /**\n * Execute one run immediately; only {@link run}'s queue calls this.\n *\n * @param feeds Map of input name to `ort.Tensor`.\n * @throws {@link InferenceError} if ORT raises any error during execution.\n */\n private async _runNow(feeds: Record<string, ort.Tensor>): Promise<Record<string, ort.Tensor>> {\n try {\n const result = await this._session.run(this._asDeclaredTypes(feeds));\n return result as Record<string, ort.Tensor>;\n } catch (err) {\n throw new InferenceError(`Inference failed: ${(err as Error).message}`, { cause: err });\n }\n }\n\n /**\n * Rebuild any feed whose type does not match what its input declares.\n *\n * ORT matches feed types against the graph exactly: a float32 tensor against\n * a `half=True` export fails the run with `Unexpected input data type`. Every\n * preprocessing path in this SDK produces `Float32Array`, on purpose — the\n * normalization arithmetic belongs in single precision — so the conversion\n * happens here, once, at the only boundary all of them pass through. A feed\n * that already carries the declared type is handed on untouched, so a caller\n * building its own half tensor pays nothing.\n *\n * @param feeds The tensors to run with.\n * @returns The same mapping, with mismatched float32 feeds converted.\n */\n private _asDeclaredTypes(feeds: Record<string, ort.Tensor>): Record<string, ort.Tensor> {\n let converted: Record<string, ort.Tensor> | null = null;\n for (const [name, tensor] of Object.entries(feeds)) {\n const declared = this._inputTypes[name];\n if (declared === undefined || declared === tensor.type) continue;\n if (!(tensor.data instanceof Float32Array)) continue;\n const data = toFeedData(tensor.data, declared);\n if (data === tensor.data) continue;\n converted ??= { ...feeds };\n converted[name] = new ortRuntime.Tensor(\n declared as \"float16\",\n data as unknown as Float32Array,\n tensor.dims as number[],\n );\n }\n return converted ?? feeds;\n }\n}\n"],"mappings":"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"}
|
package/dist/vision/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./core/exceptions.cjs"),t=require("./types.cjs"),n=require("./core/timing.cjs"),r=require("./results.cjs"),i=require("./labels.cjs"),a=require("./core/dtypes.cjs"),o=require("./core/graph.cjs"),s=require("./core/metadata.cjs"),c=require("./core/providers.cjs"),l=require("./core/session.cjs"),u=require("./normalization.cjs"),d=require("./io/image.cjs"),f=require("./fusion.cjs"),p=require("./preprocess/image.cjs"),m=require("./preprocess/pipeline.cjs"),h=require("./postprocess/classification.cjs"),g=require("./postprocess/detection.cjs"),_=require("./postprocess/segmentation.cjs"),v=require("./tasks/base.cjs"),y=require("./tasks/classifier.cjs"),b=require("./tasks/detectClassify.cjs"),x=require("./tasks/detector.cjs"),S=require("./tasks/segmenter.cjs");var C=`0.
|
|
1
|
+
const e=require("./core/exceptions.cjs"),t=require("./types.cjs"),n=require("./core/timing.cjs"),r=require("./results.cjs"),i=require("./labels.cjs"),a=require("./core/dtypes.cjs"),o=require("./core/graph.cjs"),s=require("./core/metadata.cjs"),c=require("./core/providers.cjs"),l=require("./core/session.cjs"),u=require("./normalization.cjs"),d=require("./io/image.cjs"),f=require("./fusion.cjs"),p=require("./preprocess/image.cjs"),m=require("./preprocess/pipeline.cjs"),h=require("./postprocess/classification.cjs"),g=require("./postprocess/detection.cjs"),_=require("./postprocess/segmentation.cjs"),v=require("./tasks/base.cjs"),y=require("./tasks/classifier.cjs"),b=require("./tasks/detectClassify.cjs"),x=require("./tasks/detector.cjs"),S=require("./tasks/segmenter.cjs");var C=`0.12.0`;exports.BoundingBox=t.BoundingBox,exports.Boxes=r.Boxes,exports.COCO_CLASSES=i.COCO_CLASSES,exports.CUSTOM_NORMALIZATION=u.CUSTOM_NORMALIZATION,exports.ClassificationResults=r.ClassificationResults,exports.Classifier=y.Classifier,exports.DEFAULT_MODEL_CACHE=l.DEFAULT_MODEL_CACHE,exports.DEFAULT_PROVIDERS=c.DEFAULT_PROVIDERS,exports.DEFAULT_TENSOR_TYPE=a.DEFAULT_TENSOR_TYPE,exports.DetectClassify=b.DetectClassify,exports.DetectClassifyResults=r.DetectClassifyResults,exports.DetectionResults=r.DetectionResults,exports.Detector=x.Detector,exports.FUSION_KIND_DETECT_CLASSIFY=f.FUSION_KIND_DETECT_CLASSIFY,exports.FUSION_KIND_DETECT_SEGMENT_CLASSIFY=f.FUSION_KIND_DETECT_SEGMENT_CLASSIFY,exports.FusionError=e.FusionError,exports.GRAPH_OPTIMIZATION_KEY=l.GRAPH_OPTIMIZATION_KEY,exports.IDENTITY_MEAN=u.IDENTITY_MEAN,exports.IDENTITY_STD=u.IDENTITY_STD,exports.IMAGENET_MEAN=u.IMAGENET_MEAN,exports.IMAGENET_STD=u.IMAGENET_STD,exports.INPUT_IMAGE=f.INPUT_IMAGE,exports.INPUT_PAD=f.INPUT_PAD,exports.INPUT_SCALE=f.INPUT_SCALE,exports.INPUT_SOURCE=f.INPUT_SOURCE,exports.ImageLoadError=e.ImageLoadError,exports.InferenceError=e.InferenceError,exports.LabelMapError=e.LabelMapError,exports.LetterboxPipeline=m.LetterboxPipeline,exports.METADATA_PREFIX=f.METADATA_PREFIX,exports.Mask=t.Mask,exports.Masks=r.Masks,exports.ModelLoadError=e.ModelLoadError,exports.NoDetectionsError=e.NoDetectionsError,exports.OUTPUT_BOXES=f.OUTPUT_BOXES,exports.OUTPUT_CLASSES=f.OUTPUT_CLASSES,exports.OUTPUT_MASKS=f.OUTPUT_MASKS,exports.OUTPUT_NUM_DETECTIONS=f.OUTPUT_NUM_DETECTIONS,exports.OUTPUT_PROBS=f.OUTPUT_PROBS,exports.OUTPUT_SCORES=f.OUTPUT_SCORES,exports.OrtSession=l.OrtSession,exports.OrtVisionError=e.OrtVisionError,exports.Probs=r.Probs,exports.ProviderNotAvailableError=e.ProviderNotAvailableError,exports.QUANTIZATION_KEY=l.QUANTIZATION_KEY,exports.RGBImage=t.RGBImage,exports.ResizePipeline=m.ResizePipeline,exports.SegmentationResults=r.SegmentationResults,exports.Segmenter=S.Segmenter,exports.SpeedTimer=n.SpeedTimer,exports.VERSION=C,exports.VisionTask=v.VisionTask,exports.asFloat32Array=a.asFloat32Array,exports.batchedNms=g.batchedNms,exports.classificationNumClasses=o.classificationNumClasses,exports.declaredShapesFrom=o.declaredShapesFrom,exports.decodeYolo=g.decodeYolo,exports.decodeYoloAnchors=g.decodeYoloAnchors,exports.decodeYoloSeg=_.decodeYoloSeg,exports.defaultLabels=i.defaultLabels,exports.detectProviders=c.detectProviders,exports.detectionNumClasses=o.detectionNumClasses,exports.fromCv2=p.fromCv2,exports.hasFloat16Array=a.hasFloat16Array,exports.isUltralyticsClassifier=u.isUltralyticsClassifier,exports.letterbox=p.letterbox,exports.letterboxToTensorData=m.letterboxToTensorData,exports.loadImage=d.loadImage,exports.modelNames=s.modelNames,exports.nms=g.nms,exports.normalize=p.normalize,exports.parseNames=s.parseNames,exports.readFusionSpec=f.readFusionSpec,exports.readModelInputTypes=s.readModelInputTypes,exports.readModelMetadata=s.readModelMetadata,exports.requireDetections=v.requireDetections,exports.resize=p.resize,exports.resizeToTensorData=m.resizeToTensorData,exports.resolveInputSize=o.resolveInputSize,exports.resolveLabels=i.resolveLabels,exports.resolveNormalization=u.resolveNormalization,exports.resolveProviders=c.resolveProviders,exports.softmax=h.softmax,exports.spatialInputSize=o.spatialInputSize,exports.tensorTypeFor=a.tensorTypeFor,exports.toCHW=p.toCHW,exports.toCv2=p.toCv2,exports.toFloat32=p.toFloat32,exports.toFloat32Tensor=p.toFloat32Tensor,exports.toTensor=p.toTensor,exports.topK=h.topK,exports.writePlanarFloat32=m.writePlanarFloat32,exports.zeroTensorData=m.zeroTensorData;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|