tempest-react-sdk 0.68.0 → 0.70.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/README.md +1 -1
- package/dist/sw/create-push-handler.cjs +1 -1
- package/dist/sw/create-push-handler.cjs.map +1 -1
- package/dist/sw/create-push-handler.js +58 -30
- package/dist/sw/create-push-handler.js.map +1 -1
- package/dist/sw.d.ts +53 -2
- package/dist/tempest-react-sdk.d.ts +53 -2
- package/dist/vision/core/canvas.cjs +1 -1
- package/dist/vision/core/canvas.cjs.map +1 -1
- package/dist/vision/core/canvas.js +37 -13
- package/dist/vision/core/canvas.js.map +1 -1
- package/dist/vision/core/dtypes.cjs +2 -0
- package/dist/vision/core/dtypes.cjs.map +1 -0
- package/dist/vision/core/dtypes.js +33 -0
- package/dist/vision/core/dtypes.js.map +1 -0
- package/dist/vision/core/graph.cjs +1 -1
- package/dist/vision/core/graph.cjs.map +1 -1
- package/dist/vision/core/graph.js +10 -2
- 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 +103 -13
- package/dist/vision/core/metadata.js.map +1 -1
- package/dist/vision/core/providers.cjs +1 -1
- package/dist/vision/core/providers.cjs.map +1 -1
- package/dist/vision/core/providers.js +9 -6
- package/dist/vision/core/providers.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 +115 -27
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/fusion.cjs +1 -1
- package/dist/vision/fusion.cjs.map +1 -1
- package/dist/vision/fusion.js +28 -23
- package/dist/vision/fusion.js.map +1 -1
- package/dist/vision/index.cjs +1 -1
- package/dist/vision/index.cjs.map +1 -1
- package/dist/vision/index.js +20 -19
- package/dist/vision/index.js.map +1 -1
- package/dist/vision/io/image.cjs +1 -1
- package/dist/vision/io/image.cjs.map +1 -1
- package/dist/vision/io/image.js +55 -20
- package/dist/vision/io/image.js.map +1 -1
- package/dist/vision/postprocess/detection.cjs +1 -1
- package/dist/vision/postprocess/detection.cjs.map +1 -1
- package/dist/vision/postprocess/detection.js +42 -51
- package/dist/vision/postprocess/detection.js.map +1 -1
- package/dist/vision/postprocess/segmentation.cjs +1 -1
- package/dist/vision/postprocess/segmentation.cjs.map +1 -1
- package/dist/vision/postprocess/segmentation.js +45 -31
- package/dist/vision/postprocess/segmentation.js.map +1 -1
- package/dist/vision/preprocess/pipeline.cjs +1 -1
- package/dist/vision/preprocess/pipeline.cjs.map +1 -1
- package/dist/vision/preprocess/pipeline.js +24 -25
- package/dist/vision/preprocess/pipeline.js.map +1 -1
- package/dist/vision/tasks/base.cjs +1 -1
- package/dist/vision/tasks/base.cjs.map +1 -1
- package/dist/vision/tasks/base.js +22 -7
- package/dist/vision/tasks/base.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js +64 -55
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision/tasks/detectClassify.cjs +1 -1
- package/dist/vision/tasks/detectClassify.cjs.map +1 -1
- package/dist/vision/tasks/detectClassify.js +80 -69
- package/dist/vision/tasks/detectClassify.js.map +1 -1
- package/dist/vision/tasks/detector.cjs +1 -1
- package/dist/vision/tasks/detector.cjs.map +1 -1
- package/dist/vision/tasks/detector.js +74 -68
- package/dist/vision/tasks/detector.js.map +1 -1
- package/dist/vision/tasks/segmenter.cjs +1 -1
- package/dist/vision/tasks/segmenter.cjs.map +1 -1
- package/dist/vision/tasks/segmenter.js +85 -62
- package/dist/vision/tasks/segmenter.js.map +1 -1
- package/dist/vision/types.cjs +1 -1
- package/dist/vision/types.cjs.map +1 -1
- package/dist/vision/types.js +24 -4
- package/dist/vision/types.js.map +1 -1
- package/dist/vision.cjs +1 -1
- package/dist/vision.d.ts +1153 -777
- package/dist/vision.js +22 -21
- package/package.json +2 -2
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/vision/core/dtypes.ts
|
|
2
|
+
var e = {
|
|
3
|
+
1: "float32",
|
|
4
|
+
2: "uint8",
|
|
5
|
+
3: "int8",
|
|
6
|
+
4: "uint16",
|
|
7
|
+
5: "int16",
|
|
8
|
+
6: "int32",
|
|
9
|
+
7: "int64",
|
|
10
|
+
9: "bool",
|
|
11
|
+
10: "float16",
|
|
12
|
+
11: "float64",
|
|
13
|
+
12: "uint32",
|
|
14
|
+
13: "uint64"
|
|
15
|
+
}, t = "float32", n = globalThis.Float16Array;
|
|
16
|
+
function r() {
|
|
17
|
+
return n !== void 0;
|
|
18
|
+
}
|
|
19
|
+
function i(n) {
|
|
20
|
+
return n === void 0 ? t : e[n] ?? "float32";
|
|
21
|
+
}
|
|
22
|
+
function a(e, t) {
|
|
23
|
+
if (t !== "float16") return e;
|
|
24
|
+
if (n === void 0) throw RangeError("This model declares a float16 input, but this environment has no Float16Array.");
|
|
25
|
+
return new n(e);
|
|
26
|
+
}
|
|
27
|
+
function o(e) {
|
|
28
|
+
return e instanceof Float32Array ? e : Float32Array.from(e);
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { t as DEFAULT_TENSOR_TYPE, o as asFloat32Array, r as hasFloat16Array, i as tensorTypeFor, a as toFeedData };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=dtypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtypes.js","names":[],"sources":["../../../src/vision/core/dtypes.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * What element type the graph declares, and what typed array that means.\n *\n * A model exported with `half=True` declares its input as `float16`, and ONNX\n * Runtime refuses a float32 feed against it:\n *\n * ```text\n * Unexpected input data type. Actual: (tensor(float)) , expected: (tensor(float16))\n * ```\n *\n * The session opens without complaint, so the failure lands on the caller's\n * first `predict()` rather than on `create()`. Preprocessing stays in\n * `Float32Array` because that is where the normalization arithmetic belongs —\n * `(value / 255 - mean) / std` in half precision loses exactly the small\n * differences normalization exists to preserve — and the conversion happens\n * once, at the feed boundary.\n *\n * Outputs travel the other way. Float16 carries 11 bits of mantissa, so at\n * pixel scale its neighbouring values are 0.5 apart around coordinate 640 and\n * 1.0 apart around 1280: decoding boxes in that type quantises every coordinate\n * before NMS and the scale-back to original-image pixels ever run. {@link\n * asFloat32Array} widens a half-precision output before the decoders touch it.\n *\n * `Float16Array` is what ORT requires for a half tensor — a `Uint16Array` of\n * the same bits is rejected — and it is not in every browser yet, so\n * {@link hasFloat16Array} exists to refuse at session creation instead of on\n * the first frame.\n */\n\n/** ONNX `TensorProto.DataType` values this SDK can name. */\nconst ELEM_TYPE_TO_TENSOR_TYPE: Readonly<Record<number, string>> = {\n 1: \"float32\",\n 2: \"uint8\",\n 3: \"int8\",\n 4: \"uint16\",\n 5: \"int16\",\n 6: \"int32\",\n 7: \"int64\",\n 9: \"bool\",\n 10: \"float16\",\n 11: \"float64\",\n 12: \"uint32\",\n 13: \"uint64\",\n};\n\n/** The element type every task preprocesses to, and the fallback when unknown. */\nexport const DEFAULT_TENSOR_TYPE = \"float32\";\n\n/**\n * The structural surface of `Float16Array` this module needs.\n *\n * Declared here rather than pulled from `lib.es2025`: the package targets\n * ES2022 so it builds for consumers on older TypeScript, and the only thing\n * needed is \"an array-like of numbers ORT recognises as half precision\".\n */\nexport interface Float16ArrayLike {\n readonly length: number;\n readonly buffer: ArrayBufferLike;\n [index: number]: number;\n}\n\ninterface Float16ArrayConstructor {\n new (input: ArrayLike<number> | number): Float16ArrayLike;\n}\n\nconst FLOAT16_ARRAY = (globalThis as { Float16Array?: Float16ArrayConstructor }).Float16Array;\n\n/**\n * Whether this environment can build a half-precision tensor at all.\n *\n * @returns `true` when the runtime exposes `Float16Array`. ORT rejects any\n * other typed array for a `float16` tensor, so a `false` here means half\n * precision is unreachable in this browser no matter what the model declares.\n */\nexport function hasFloat16Array(): boolean {\n return FLOAT16_ARRAY !== undefined;\n}\n\n/**\n * Name the tensor type an ONNX element type maps to.\n *\n * @param elemType A `TensorProto.DataType` value read off the graph.\n * @returns The ORT tensor type name, or `\"float32\"` for anything unrecognised —\n * which is what every task produces anyway, so an unknown type surfaces as\n * ORT's own type error against the real graph rather than as a lookup miss.\n */\nexport function tensorTypeFor(elemType: number | undefined): string {\n if (elemType === undefined) return DEFAULT_TENSOR_TYPE;\n return ELEM_TYPE_TO_TENSOR_TYPE[elemType] ?? DEFAULT_TENSOR_TYPE;\n}\n\n/**\n * Convert a preprocessed float32 buffer to the type a feed must carry.\n *\n * @param data The preprocessed planar buffer.\n * @param tensorType The tensor type the input declares, from\n * {@link tensorTypeFor}.\n * @returns `data` itself for a float32 input, or a `Float16Array` holding the\n * same values for a half-precision one.\n * @throws {RangeError} If half precision is asked for and the runtime has no\n * `Float16Array`. Callers convert this into a `ModelLoadError` at session\n * creation, so it never reaches a `predict()`.\n */\nexport function toFeedData(\n data: Float32Array,\n tensorType: string,\n): Float32Array | Float16ArrayLike {\n if (tensorType !== \"float16\") return data;\n if (FLOAT16_ARRAY === undefined) {\n throw new RangeError(\n \"This model declares a float16 input, but this environment has no Float16Array.\",\n );\n }\n return new FLOAT16_ARRAY(data);\n}\n\n/**\n * Widen a model output to `Float32Array`, without copying when it already is.\n *\n * @param data A tensor's `data`, as ORT returned it.\n * @returns The same values as a `Float32Array`. A float32 output is passed\n * through untouched; anything else is copied once.\n */\nexport function asFloat32Array(data: unknown): Float32Array {\n if (data instanceof Float32Array) return data;\n return Float32Array.from(data as ArrayLike<number>);\n}\n"],"mappings":";AA+BA,IAAM,IAA6D;CAC/D,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACR,GAGa,IAAsB,WAmB7B,IAAiB,WAA0D;AASjF,SAAgB,IAA2B;CACvC,OAAO,MAAkB,KAAA;AAC7B;AAUA,SAAgB,EAAc,GAAsC;CAEhE,OADI,MAAa,KAAA,IAAkB,IAC5B,EAAyB,MAAA;AACpC;AAcA,SAAgB,EACZ,GACA,GAC+B;CAC/B,IAAI,MAAe,WAAW,OAAO;CACrC,IAAI,MAAkB,KAAA,GAClB,MAAU,WACN,gFACJ;CAEJ,OAAO,IAAI,EAAc,CAAI;AACjC;AASA,SAAgB,EAAe,GAA6B;CAExD,OADI,aAAgB,eAAqB,IAClC,aAAa,KAAK,CAAyB;AACtD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){return e===void 0?[]:e.map(e=>e.isTensor?e.shape.map(e=>typeof e==`number`&&Number.isInteger(e)&&e>0?e:null):[])}function t(e){if(e.length!==4)return null;let t=e[2],n=e[3];return t==null||n==null?null:[n,t]}function n(e){let t=e.filter(e=>e!==null&&e>1);if(t.length===0)return null;let n=Math.min(...t);return n<5?null:n-4}function r(e){let t=e[e.length-1];return t==null||t<1?null:t}function
|
|
1
|
+
function e(e){return e===void 0?[]:e.map(e=>e.isTensor?e.shape.map(e=>typeof e==`number`&&Number.isInteger(e)&&e>0?e:null):[])}function t(e){if(e.length!==4)return null;let t=e[2],n=e[3];return t==null||n==null?null:[n,t]}function n(e){let t=e.filter(e=>e!==null&&e>1);if(t.length===0)return null;let n=Math.min(...t);return n<5?null:n-4}function r(e){let t=e.find(e=>e.length===3);if(t===void 0)return null;let n=t.filter(e=>e!==null&&e>1);if(n.length===0)return null;let r=Math.min(...n),i=e.find(e=>e.length===4)?.[1],a=typeof i==`number`&&i>0?i:32,o=r-4-a;return o>0?o:null}function i(e){let t=e[e.length-1];return t==null||t<1?null:t}function a(e){let n=e.graphShape===void 0?null:t(e.graphShape),r=e.requested;return n===null?r??e.fallback:(r!==void 0&&(r[0]!==n[0]||r[1]!==n[1])&&console.warn(`[ort-vision-sdk] The model declares a ${n[0]}x${n[1]} input; ignoring the requested ${r[0]}x${r[1]}, which ONNX Runtime would reject.`),n)}exports.classificationNumClasses=i,exports.declaredShapesFrom=e,exports.detectionNumClasses=n,exports.resolveInputSize=a,exports.segmentationNumClasses=r,exports.spatialInputSize=t;
|
|
2
2
|
//# sourceMappingURL=graph.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.cjs","names":[],"sources":["../../../src/vision/core/graph.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * What the ONNX graph itself says about its inputs.\n *\n * The resolution a session must be fed at is a property of the exported model,\n * not of the configuration around it. Feeding a 640x640 tensor to a graph\n * exported at 224x224 makes ORT abort the run with\n * `Got invalid dimensions for input: images ... Got: 640 Expected: 224`, and the\n * caller has no way to see that coming from the outside — the number lives in\n * the file. So the SDK reads it from the graph and treats any configured size as\n * a fallback for when the graph leaves it open.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\n/**\n * One declared dimension: a number when the graph pins it, `null` when the\n * dimension is symbolic (dynamic).\n */\nexport type DeclaredDim = number | null;\n\n/** A declared input/output shape, dynamic axes appearing as `null`. */\nexport type DeclaredShape = readonly DeclaredDim[];\n\n/**\n * Convert ORT value metadata into declared shapes.\n *\n * @param metadata Metadata as reported by `InferenceSession.inputMetadata`, or\n * `undefined` on ORT builds that predate it (added in onnxruntime 1.21).\n * @returns One shape per value, in declaration order. Non-tensor values and\n * builds without metadata yield empty shapes, which read as \"nothing\n * declared\" everywhere downstream.\n */\nexport function declaredShapesFrom(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n): readonly DeclaredShape[] {\n if (metadata === undefined) return [];\n return metadata.map((value) =>\n value.isTensor\n ? value.shape.map((dim) =>\n typeof dim === \"number\" && Number.isInteger(dim) && dim > 0 ? dim : null,\n )\n : [],\n );\n}\n\n/**\n * Read the spatial input size out of a declared NCHW shape.\n *\n * @param shape The declared shape of the model's image input.\n * @returns `[width, height]` in pixels, or `null` when the shape is not 4D or\n * leaves either spatial axis dynamic — in which case the model accepts more\n * than one resolution and there is nothing to correct.\n */\nexport function spatialInputSize(shape: DeclaredShape): readonly [number, number] | null {\n if (shape.length !== 4) return null;\n const height = shape[2];\n const width = shape[3];\n if (height === null || height === undefined || width === null || width === undefined)\n return null;\n return [width, height];\n}\n\n/**\n * Infer how many classes a YOLO detection/segmentation head emits.\n *\n * Such a head declares `(B, 4 + nc, N)` — four box coordinates stacked above one\n * score per class, over `N` candidate anchors. `N` is in the thousands and the\n * batch is 1, so the channel axis is the smallest static axis above 1.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the shape leaves it undeterminable —\n * fully dynamic, or too small to hold boxes plus at least one class.\n */\nexport function detectionNumClasses(shape: DeclaredShape): number | null {\n const staticDims = shape.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n if (channels < 5) return null;\n return channels - 4;\n}\n\n/**\n * Infer how many classes a classification head emits.\n *\n * A classifier declares `(B, nc)`, so the count is the last static axis.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the last axis is dynamic or absent.\n */\nexport function classificationNumClasses(shape: DeclaredShape): number | null {\n const last = shape[shape.length - 1];\n if (last === null || last === undefined || last < 1) return null;\n return last;\n}\n\nexport interface ResolveInputSizeOptions {\n /** Declared shape of the model's image input, from {@link declaredShapesFrom}. */\n readonly graphShape?: DeclaredShape;\n /** Size the caller asked for, if any. */\n readonly requested?: readonly [number, number];\n /** Size to use when neither the graph nor the caller pins one. */\n readonly fallback: readonly [number, number];\n}\n\n/**\n * Decide the input size a task will preprocess to.\n *\n * Precedence is graph → caller → fallback. The graph wins over an explicit\n * `inputSize` because a static shape is not a preference, it is what ORT will\n * accept: honoring the caller there would only turn a fixable mismatch into a\n * failed run. A disagreement is a configuration bug in the caller, so it is\n * reported through `console.warn` instead of being swallowed.\n *\n * @param options Graph shape, requested size and per-task fallback.\n * @returns The `[width, height]` to preprocess to.\n */\nexport function resolveInputSize(options: ResolveInputSizeOptions): readonly [number, number] {\n const graph = options.graphShape === undefined ? null : spatialInputSize(options.graphShape);\n const requested = options.requested;\n if (graph === null) return requested ?? options.fallback;\n if (requested !== undefined && (requested[0] !== graph[0] || requested[1] !== graph[1])) {\n console.warn(\n `[ort-vision-sdk] The model declares a ${graph[0]}x${graph[1]} input; ` +\n `ignoring the requested ${requested[0]}x${requested[1]}, which ONNX Runtime would reject.`,\n );\n }\n return graph;\n}\n"],"mappings":"AAiCA,SAAgB,EACZ,EACwB,CAExB,OADI,IAAa,IAAA,GAAkB,CAAC,EAC7B,EAAS,IAAK,GACjB,EAAM,SACA,EAAM,MAAM,IAAK,GACb,OAAO,GAAQ,UAAY,OAAO,UAAU,CAAG,GAAK,EAAM,EAAI,EAAM,IACxE,EACA,CAAC,CACX,CACJ,CAUA,SAAgB,EAAiB,EAAwD,CACrF,GAAI,EAAM,SAAW,EAAG,OAAO,KAC/B,IAAM,EAAS,EAAM,GACf,EAAQ,EAAM,GAGpB,OAFI,GAAW,MAAgC,GAAU,KAC9C,KACJ,CAAC,EAAO,CAAM,CACzB,CAaA,SAAgB,EAAoB,EAAqC,CACrE,IAAM,EAAa,EAAM,OAAQ,GAAuB,IAAQ,MAAQ,EAAM,CAAC,EAC/E,GAAI,EAAW,SAAW,EAAG,OAAO,KACpC,IAAM,EAAW,KAAK,IAAI,GAAG,CAAU,EAEvC,OADI,EAAW,EAAU,KAClB,EAAW,CACtB,CAUA,SAAgB,EAAyB,EAAqC,CAC1E,IAAM,EAAO,EAAM,EAAM,OAAS,GAElC,OADI,GAAS,MAA8B,EAAO,EAAU,KACrD,CACX,CAuBA,SAAgB,EAAiB,EAA6D,CAC1F,IAAM,EAAQ,EAAQ,aAAe,IAAA,GAAY,KAAO,EAAiB,EAAQ,UAAU,EACrF,EAAY,EAAQ,UAQ1B,OAPI,IAAU,KAAa,GAAa,EAAQ,UAC5C,IAAc,IAAA,KAAc,EAAU,KAAO,EAAM,IAAM,EAAU,KAAO,EAAM,KAChF,QAAQ,KACJ,yCAAyC,EAAM,GAAG,GAAG,EAAM,GAAG,iCAChC,EAAU,GAAG,GAAG,EAAU,GAAG,mCAC/D,EAEG,EACX"}
|
|
1
|
+
{"version":3,"file":"graph.cjs","names":[],"sources":["../../../src/vision/core/graph.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * What the ONNX graph itself says about its inputs.\n *\n * The resolution a session must be fed at is a property of the exported model,\n * not of the configuration around it. Feeding a 640x640 tensor to a graph\n * exported at 224x224 makes ORT abort the run with\n * `Got invalid dimensions for input: images ... Got: 640 Expected: 224`, and the\n * caller has no way to see that coming from the outside — the number lives in\n * the file. So the SDK reads it from the graph and treats any configured size as\n * a fallback for when the graph leaves it open.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\n/**\n * One declared dimension: a number when the graph pins it, `null` when the\n * dimension is symbolic (dynamic).\n */\nexport type DeclaredDim = number | null;\n\n/** A declared input/output shape, dynamic axes appearing as `null`. */\nexport type DeclaredShape = readonly DeclaredDim[];\n\n/**\n * Convert ORT value metadata into declared shapes.\n *\n * @param metadata Metadata as reported by `InferenceSession.inputMetadata`, or\n * `undefined` on ORT builds that predate it (added in onnxruntime 1.21).\n * @returns One shape per value, in declaration order. Non-tensor values and\n * builds without metadata yield empty shapes, which read as \"nothing\n * declared\" everywhere downstream.\n */\nexport function declaredShapesFrom(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n): readonly DeclaredShape[] {\n if (metadata === undefined) return [];\n return metadata.map((value) =>\n value.isTensor\n ? value.shape.map((dim) =>\n typeof dim === \"number\" && Number.isInteger(dim) && dim > 0 ? dim : null,\n )\n : [],\n );\n}\n\n/**\n * Read the spatial input size out of a declared NCHW shape.\n *\n * @param shape The declared shape of the model's image input.\n * @returns `[width, height]` in pixels, or `null` when the shape is not 4D or\n * leaves either spatial axis dynamic — in which case the model accepts more\n * than one resolution and there is nothing to correct.\n */\nexport function spatialInputSize(shape: DeclaredShape): readonly [number, number] | null {\n if (shape.length !== 4) return null;\n const height = shape[2];\n const width = shape[3];\n if (height === null || height === undefined || width === null || width === undefined)\n return null;\n return [width, height];\n}\n\n/**\n * Infer how many classes a YOLO detection/segmentation head emits.\n *\n * Such a head declares `(B, 4 + nc, N)` — four box coordinates stacked above one\n * score per class, over `N` candidate anchors. `N` is in the thousands and the\n * batch is 1, so the channel axis is the smallest static axis above 1.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the shape leaves it undeterminable —\n * fully dynamic, or too small to hold boxes plus at least one class.\n */\nexport function detectionNumClasses(shape: DeclaredShape): number | null {\n const staticDims = shape.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n if (channels < 5) return null;\n return channels - 4;\n}\n\n/**\n * Mask coefficients per anchor when no prototype shape says otherwise.\n *\n * Every Ultralytics seg head (v8, v11) emits 32; it is the fallback when the\n * prototype output's channel axis is dynamic or the runtime reports no shapes.\n */\nconst DEFAULT_MASK_COEFS = 32;\n\n/**\n * Infer how many classes a YOLO segmentation head emits.\n *\n * The per-anchor output declares `(B, 4 + nc + nm, N)`: the detection layout\n * with `nm` mask coefficients stacked under the class scores. Reading it with\n * {@link detectionNumClasses} counts those coefficients as classes — 33 for a\n * one-class YOLO11n-seg, 112 for a COCO one — and the label check then rejects\n * the model's own baked-in names. `nm` is the channel axis of the prototype\n * output `(B, nm, H, W)`, so it is read from there.\n *\n * @param shapes Declared shapes of every output, in declaration order.\n * @returns The class count, or `null` when the per-anchor shape is missing or\n * leaves it undeterminable.\n */\nexport function segmentationNumClasses(shapes: readonly DeclaredShape[]): number | null {\n const perAnchor = shapes.find((shape) => shape.length === 3);\n if (perAnchor === undefined) return null;\n const staticDims = perAnchor.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n const prototypes = shapes.find((shape) => shape.length === 4);\n const declared = prototypes?.[1];\n const coefs = typeof declared === \"number\" && declared > 0 ? declared : DEFAULT_MASK_COEFS;\n const classes = channels - 4 - coefs;\n return classes > 0 ? classes : null;\n}\n\n/**\n * Infer how many classes a classification head emits.\n *\n * A classifier declares `(B, nc)`, so the count is the last static axis.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the last axis is dynamic or absent.\n */\nexport function classificationNumClasses(shape: DeclaredShape): number | null {\n const last = shape[shape.length - 1];\n if (last === null || last === undefined || last < 1) return null;\n return last;\n}\n\nexport interface ResolveInputSizeOptions {\n /** Declared shape of the model's image input, from {@link declaredShapesFrom}. */\n readonly graphShape?: DeclaredShape;\n /** Size the caller asked for, if any. */\n readonly requested?: readonly [number, number];\n /** Size to use when neither the graph nor the caller pins one. */\n readonly fallback: readonly [number, number];\n}\n\n/**\n * Decide the input size a task will preprocess to.\n *\n * Precedence is graph → caller → fallback. The graph wins over an explicit\n * `inputSize` because a static shape is not a preference, it is what ORT will\n * accept: honoring the caller there would only turn a fixable mismatch into a\n * failed run. A disagreement is a configuration bug in the caller, so it is\n * reported through `console.warn` instead of being swallowed.\n *\n * @param options Graph shape, requested size and per-task fallback.\n * @returns The `[width, height]` to preprocess to.\n */\nexport function resolveInputSize(options: ResolveInputSizeOptions): readonly [number, number] {\n const graph = options.graphShape === undefined ? null : spatialInputSize(options.graphShape);\n const requested = options.requested;\n if (graph === null) return requested ?? options.fallback;\n if (requested !== undefined && (requested[0] !== graph[0] || requested[1] !== graph[1])) {\n console.warn(\n `[ort-vision-sdk] The model declares a ${graph[0]}x${graph[1]} input; ` +\n `ignoring the requested ${requested[0]}x${requested[1]}, which ONNX Runtime would reject.`,\n );\n }\n return graph;\n}\n"],"mappings":"AAiCA,SAAgB,EACZ,EACwB,CAExB,OADI,IAAa,IAAA,GAAkB,CAAC,EAC7B,EAAS,IAAK,GACjB,EAAM,SACA,EAAM,MAAM,IAAK,GACb,OAAO,GAAQ,UAAY,OAAO,UAAU,CAAG,GAAK,EAAM,EAAI,EAAM,IACxE,EACA,CAAC,CACX,CACJ,CAUA,SAAgB,EAAiB,EAAwD,CACrF,GAAI,EAAM,SAAW,EAAG,OAAO,KAC/B,IAAM,EAAS,EAAM,GACf,EAAQ,EAAM,GAGpB,OAFI,GAAW,MAAgC,GAAU,KAC9C,KACJ,CAAC,EAAO,CAAM,CACzB,CAaA,SAAgB,EAAoB,EAAqC,CACrE,IAAM,EAAa,EAAM,OAAQ,GAAuB,IAAQ,MAAQ,EAAM,CAAC,EAC/E,GAAI,EAAW,SAAW,EAAG,OAAO,KACpC,IAAM,EAAW,KAAK,IAAI,GAAG,CAAU,EAEvC,OADI,EAAW,EAAU,KAClB,EAAW,CACtB,CAwBA,SAAgB,EAAuB,EAAiD,CACpF,IAAM,EAAY,EAAO,KAAM,GAAU,EAAM,SAAW,CAAC,EAC3D,GAAI,IAAc,IAAA,GAAW,OAAO,KACpC,IAAM,EAAa,EAAU,OAAQ,GAAuB,IAAQ,MAAQ,EAAM,CAAC,EACnF,GAAI,EAAW,SAAW,EAAG,OAAO,KACpC,IAAM,EAAW,KAAK,IAAI,GAAG,CAAU,EAEjC,EADa,EAAO,KAAM,GAAU,EAAM,SAAW,CAC1C,CAAA,GAAa,GACxB,EAAQ,OAAO,GAAa,UAAY,EAAW,EAAI,EAAW,GAClE,EAAU,EAAW,EAAI,EAC/B,OAAO,EAAU,EAAI,EAAU,IACnC,CAUA,SAAgB,EAAyB,EAAqC,CAC1E,IAAM,EAAO,EAAM,EAAM,OAAS,GAElC,OADI,GAAS,MAA8B,EAAO,EAAU,KACrD,CACX,CAuBA,SAAgB,EAAiB,EAA6D,CAC1F,IAAM,EAAQ,EAAQ,aAAe,IAAA,GAAY,KAAO,EAAiB,EAAQ,UAAU,EACrF,EAAY,EAAQ,UAQ1B,OAPI,IAAU,KAAa,GAAa,EAAQ,UAC5C,IAAc,IAAA,KAAc,EAAU,KAAO,EAAM,IAAM,EAAU,KAAO,EAAM,KAChF,QAAQ,KACJ,yCAAyC,EAAM,GAAG,GAAG,EAAM,GAAG,iCAChC,EAAU,GAAG,GAAG,EAAU,GAAG,mCAC/D,EAEG,EACX"}
|
|
@@ -14,14 +14,22 @@ function n(e) {
|
|
|
14
14
|
return n < 5 ? null : n - 4;
|
|
15
15
|
}
|
|
16
16
|
function r(e) {
|
|
17
|
+
let t = e.find((e) => e.length === 3);
|
|
18
|
+
if (t === void 0) return null;
|
|
19
|
+
let n = t.filter((e) => e !== null && e > 1);
|
|
20
|
+
if (n.length === 0) return null;
|
|
21
|
+
let r = Math.min(...n), i = e.find((e) => e.length === 4)?.[1], a = typeof i == "number" && i > 0 ? i : 32, o = r - 4 - a;
|
|
22
|
+
return o > 0 ? o : null;
|
|
23
|
+
}
|
|
24
|
+
function i(e) {
|
|
17
25
|
let t = e[e.length - 1];
|
|
18
26
|
return t == null || t < 1 ? null : t;
|
|
19
27
|
}
|
|
20
|
-
function
|
|
28
|
+
function a(e) {
|
|
21
29
|
let n = e.graphShape === void 0 ? null : t(e.graphShape), r = e.requested;
|
|
22
30
|
return n === null ? r ?? e.fallback : (r !== void 0 && (r[0] !== n[0] || r[1] !== n[1]) && console.warn(`[ort-vision-sdk] The model declares a ${n[0]}x${n[1]} input; ignoring the requested ${r[0]}x${r[1]}, which ONNX Runtime would reject.`), n);
|
|
23
31
|
}
|
|
24
32
|
//#endregion
|
|
25
|
-
export {
|
|
33
|
+
export { i as classificationNumClasses, e as declaredShapesFrom, n as detectionNumClasses, a as resolveInputSize, r as segmentationNumClasses, t as spatialInputSize };
|
|
26
34
|
|
|
27
35
|
//# sourceMappingURL=graph.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","names":[],"sources":["../../../src/vision/core/graph.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * What the ONNX graph itself says about its inputs.\n *\n * The resolution a session must be fed at is a property of the exported model,\n * not of the configuration around it. Feeding a 640x640 tensor to a graph\n * exported at 224x224 makes ORT abort the run with\n * `Got invalid dimensions for input: images ... Got: 640 Expected: 224`, and the\n * caller has no way to see that coming from the outside — the number lives in\n * the file. So the SDK reads it from the graph and treats any configured size as\n * a fallback for when the graph leaves it open.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\n/**\n * One declared dimension: a number when the graph pins it, `null` when the\n * dimension is symbolic (dynamic).\n */\nexport type DeclaredDim = number | null;\n\n/** A declared input/output shape, dynamic axes appearing as `null`. */\nexport type DeclaredShape = readonly DeclaredDim[];\n\n/**\n * Convert ORT value metadata into declared shapes.\n *\n * @param metadata Metadata as reported by `InferenceSession.inputMetadata`, or\n * `undefined` on ORT builds that predate it (added in onnxruntime 1.21).\n * @returns One shape per value, in declaration order. Non-tensor values and\n * builds without metadata yield empty shapes, which read as \"nothing\n * declared\" everywhere downstream.\n */\nexport function declaredShapesFrom(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n): readonly DeclaredShape[] {\n if (metadata === undefined) return [];\n return metadata.map((value) =>\n value.isTensor\n ? value.shape.map((dim) =>\n typeof dim === \"number\" && Number.isInteger(dim) && dim > 0 ? dim : null,\n )\n : [],\n );\n}\n\n/**\n * Read the spatial input size out of a declared NCHW shape.\n *\n * @param shape The declared shape of the model's image input.\n * @returns `[width, height]` in pixels, or `null` when the shape is not 4D or\n * leaves either spatial axis dynamic — in which case the model accepts more\n * than one resolution and there is nothing to correct.\n */\nexport function spatialInputSize(shape: DeclaredShape): readonly [number, number] | null {\n if (shape.length !== 4) return null;\n const height = shape[2];\n const width = shape[3];\n if (height === null || height === undefined || width === null || width === undefined)\n return null;\n return [width, height];\n}\n\n/**\n * Infer how many classes a YOLO detection/segmentation head emits.\n *\n * Such a head declares `(B, 4 + nc, N)` — four box coordinates stacked above one\n * score per class, over `N` candidate anchors. `N` is in the thousands and the\n * batch is 1, so the channel axis is the smallest static axis above 1.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the shape leaves it undeterminable —\n * fully dynamic, or too small to hold boxes plus at least one class.\n */\nexport function detectionNumClasses(shape: DeclaredShape): number | null {\n const staticDims = shape.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n if (channels < 5) return null;\n return channels - 4;\n}\n\n/**\n * Infer how many classes a classification head emits.\n *\n * A classifier declares `(B, nc)`, so the count is the last static axis.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the last axis is dynamic or absent.\n */\nexport function classificationNumClasses(shape: DeclaredShape): number | null {\n const last = shape[shape.length - 1];\n if (last === null || last === undefined || last < 1) return null;\n return last;\n}\n\nexport interface ResolveInputSizeOptions {\n /** Declared shape of the model's image input, from {@link declaredShapesFrom}. */\n readonly graphShape?: DeclaredShape;\n /** Size the caller asked for, if any. */\n readonly requested?: readonly [number, number];\n /** Size to use when neither the graph nor the caller pins one. */\n readonly fallback: readonly [number, number];\n}\n\n/**\n * Decide the input size a task will preprocess to.\n *\n * Precedence is graph → caller → fallback. The graph wins over an explicit\n * `inputSize` because a static shape is not a preference, it is what ORT will\n * accept: honoring the caller there would only turn a fixable mismatch into a\n * failed run. A disagreement is a configuration bug in the caller, so it is\n * reported through `console.warn` instead of being swallowed.\n *\n * @param options Graph shape, requested size and per-task fallback.\n * @returns The `[width, height]` to preprocess to.\n */\nexport function resolveInputSize(options: ResolveInputSizeOptions): readonly [number, number] {\n const graph = options.graphShape === undefined ? null : spatialInputSize(options.graphShape);\n const requested = options.requested;\n if (graph === null) return requested ?? options.fallback;\n if (requested !== undefined && (requested[0] !== graph[0] || requested[1] !== graph[1])) {\n console.warn(\n `[ort-vision-sdk] The model declares a ${graph[0]}x${graph[1]} input; ` +\n `ignoring the requested ${requested[0]}x${requested[1]}, which ONNX Runtime would reject.`,\n );\n }\n return graph;\n}\n"],"mappings":";AAiCA,SAAgB,EACZ,GACwB;CAExB,OADI,MAAa,KAAA,IAAkB,CAAC,IAC7B,EAAS,KAAK,MACjB,EAAM,WACA,EAAM,MAAM,KAAK,MACb,OAAO,KAAQ,YAAY,OAAO,UAAU,CAAG,KAAK,IAAM,IAAI,IAAM,IACxE,IACA,CAAC,CACX;AACJ;AAUA,SAAgB,EAAiB,GAAwD;CACrF,IAAI,EAAM,WAAW,GAAG,OAAO;CAC/B,IAAM,IAAS,EAAM,IACf,IAAQ,EAAM;CAGpB,OAFI,KAAW,QAAgC,KAAU,OAC9C,OACJ,CAAC,GAAO,CAAM;AACzB;AAaA,SAAgB,EAAoB,GAAqC;CACrE,IAAM,IAAa,EAAM,QAAQ,MAAuB,MAAQ,QAAQ,IAAM,CAAC;CAC/E,IAAI,EAAW,WAAW,GAAG,OAAO;CACpC,IAAM,IAAW,KAAK,IAAI,GAAG,CAAU;CAEvC,OADI,IAAW,IAAU,OAClB,IAAW;AACtB;AAUA,SAAgB,EAAyB,GAAqC;CAC1E,IAAM,IAAO,EAAM,EAAM,SAAS;CAElC,OADI,KAAS,QAA8B,IAAO,IAAU,OACrD;AACX;AAuBA,SAAgB,EAAiB,GAA6D;CAC1F,IAAM,IAAQ,EAAQ,eAAe,KAAA,IAAY,OAAO,EAAiB,EAAQ,UAAU,GACrF,IAAY,EAAQ;CAQ1B,OAPI,MAAU,OAAa,KAAa,EAAQ,YAC5C,MAAc,KAAA,MAAc,EAAU,OAAO,EAAM,MAAM,EAAU,OAAO,EAAM,OAChF,QAAQ,KACJ,yCAAyC,EAAM,GAAG,GAAG,EAAM,GAAG,iCAChC,EAAU,GAAG,GAAG,EAAU,GAAG,mCAC/D,GAEG;AACX"}
|
|
1
|
+
{"version":3,"file":"graph.js","names":[],"sources":["../../../src/vision/core/graph.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * What the ONNX graph itself says about its inputs.\n *\n * The resolution a session must be fed at is a property of the exported model,\n * not of the configuration around it. Feeding a 640x640 tensor to a graph\n * exported at 224x224 makes ORT abort the run with\n * `Got invalid dimensions for input: images ... Got: 640 Expected: 224`, and the\n * caller has no way to see that coming from the outside — the number lives in\n * the file. So the SDK reads it from the graph and treats any configured size as\n * a fallback for when the graph leaves it open.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\n/**\n * One declared dimension: a number when the graph pins it, `null` when the\n * dimension is symbolic (dynamic).\n */\nexport type DeclaredDim = number | null;\n\n/** A declared input/output shape, dynamic axes appearing as `null`. */\nexport type DeclaredShape = readonly DeclaredDim[];\n\n/**\n * Convert ORT value metadata into declared shapes.\n *\n * @param metadata Metadata as reported by `InferenceSession.inputMetadata`, or\n * `undefined` on ORT builds that predate it (added in onnxruntime 1.21).\n * @returns One shape per value, in declaration order. Non-tensor values and\n * builds without metadata yield empty shapes, which read as \"nothing\n * declared\" everywhere downstream.\n */\nexport function declaredShapesFrom(\n metadata: readonly ort.InferenceSession.ValueMetadata[] | undefined,\n): readonly DeclaredShape[] {\n if (metadata === undefined) return [];\n return metadata.map((value) =>\n value.isTensor\n ? value.shape.map((dim) =>\n typeof dim === \"number\" && Number.isInteger(dim) && dim > 0 ? dim : null,\n )\n : [],\n );\n}\n\n/**\n * Read the spatial input size out of a declared NCHW shape.\n *\n * @param shape The declared shape of the model's image input.\n * @returns `[width, height]` in pixels, or `null` when the shape is not 4D or\n * leaves either spatial axis dynamic — in which case the model accepts more\n * than one resolution and there is nothing to correct.\n */\nexport function spatialInputSize(shape: DeclaredShape): readonly [number, number] | null {\n if (shape.length !== 4) return null;\n const height = shape[2];\n const width = shape[3];\n if (height === null || height === undefined || width === null || width === undefined)\n return null;\n return [width, height];\n}\n\n/**\n * Infer how many classes a YOLO detection/segmentation head emits.\n *\n * Such a head declares `(B, 4 + nc, N)` — four box coordinates stacked above one\n * score per class, over `N` candidate anchors. `N` is in the thousands and the\n * batch is 1, so the channel axis is the smallest static axis above 1.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the shape leaves it undeterminable —\n * fully dynamic, or too small to hold boxes plus at least one class.\n */\nexport function detectionNumClasses(shape: DeclaredShape): number | null {\n const staticDims = shape.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n if (channels < 5) return null;\n return channels - 4;\n}\n\n/**\n * Mask coefficients per anchor when no prototype shape says otherwise.\n *\n * Every Ultralytics seg head (v8, v11) emits 32; it is the fallback when the\n * prototype output's channel axis is dynamic or the runtime reports no shapes.\n */\nconst DEFAULT_MASK_COEFS = 32;\n\n/**\n * Infer how many classes a YOLO segmentation head emits.\n *\n * The per-anchor output declares `(B, 4 + nc + nm, N)`: the detection layout\n * with `nm` mask coefficients stacked under the class scores. Reading it with\n * {@link detectionNumClasses} counts those coefficients as classes — 33 for a\n * one-class YOLO11n-seg, 112 for a COCO one — and the label check then rejects\n * the model's own baked-in names. `nm` is the channel axis of the prototype\n * output `(B, nm, H, W)`, so it is read from there.\n *\n * @param shapes Declared shapes of every output, in declaration order.\n * @returns The class count, or `null` when the per-anchor shape is missing or\n * leaves it undeterminable.\n */\nexport function segmentationNumClasses(shapes: readonly DeclaredShape[]): number | null {\n const perAnchor = shapes.find((shape) => shape.length === 3);\n if (perAnchor === undefined) return null;\n const staticDims = perAnchor.filter((dim): dim is number => dim !== null && dim > 1);\n if (staticDims.length === 0) return null;\n const channels = Math.min(...staticDims);\n const prototypes = shapes.find((shape) => shape.length === 4);\n const declared = prototypes?.[1];\n const coefs = typeof declared === \"number\" && declared > 0 ? declared : DEFAULT_MASK_COEFS;\n const classes = channels - 4 - coefs;\n return classes > 0 ? classes : null;\n}\n\n/**\n * Infer how many classes a classification head emits.\n *\n * A classifier declares `(B, nc)`, so the count is the last static axis.\n *\n * @param shape Declared shape of the model's first output.\n * @returns The class count, or `null` when the last axis is dynamic or absent.\n */\nexport function classificationNumClasses(shape: DeclaredShape): number | null {\n const last = shape[shape.length - 1];\n if (last === null || last === undefined || last < 1) return null;\n return last;\n}\n\nexport interface ResolveInputSizeOptions {\n /** Declared shape of the model's image input, from {@link declaredShapesFrom}. */\n readonly graphShape?: DeclaredShape;\n /** Size the caller asked for, if any. */\n readonly requested?: readonly [number, number];\n /** Size to use when neither the graph nor the caller pins one. */\n readonly fallback: readonly [number, number];\n}\n\n/**\n * Decide the input size a task will preprocess to.\n *\n * Precedence is graph → caller → fallback. The graph wins over an explicit\n * `inputSize` because a static shape is not a preference, it is what ORT will\n * accept: honoring the caller there would only turn a fixable mismatch into a\n * failed run. A disagreement is a configuration bug in the caller, so it is\n * reported through `console.warn` instead of being swallowed.\n *\n * @param options Graph shape, requested size and per-task fallback.\n * @returns The `[width, height]` to preprocess to.\n */\nexport function resolveInputSize(options: ResolveInputSizeOptions): readonly [number, number] {\n const graph = options.graphShape === undefined ? null : spatialInputSize(options.graphShape);\n const requested = options.requested;\n if (graph === null) return requested ?? options.fallback;\n if (requested !== undefined && (requested[0] !== graph[0] || requested[1] !== graph[1])) {\n console.warn(\n `[ort-vision-sdk] The model declares a ${graph[0]}x${graph[1]} input; ` +\n `ignoring the requested ${requested[0]}x${requested[1]}, which ONNX Runtime would reject.`,\n );\n }\n return graph;\n}\n"],"mappings":";AAiCA,SAAgB,EACZ,GACwB;CAExB,OADI,MAAa,KAAA,IAAkB,CAAC,IAC7B,EAAS,KAAK,MACjB,EAAM,WACA,EAAM,MAAM,KAAK,MACb,OAAO,KAAQ,YAAY,OAAO,UAAU,CAAG,KAAK,IAAM,IAAI,IAAM,IACxE,IACA,CAAC,CACX;AACJ;AAUA,SAAgB,EAAiB,GAAwD;CACrF,IAAI,EAAM,WAAW,GAAG,OAAO;CAC/B,IAAM,IAAS,EAAM,IACf,IAAQ,EAAM;CAGpB,OAFI,KAAW,QAAgC,KAAU,OAC9C,OACJ,CAAC,GAAO,CAAM;AACzB;AAaA,SAAgB,EAAoB,GAAqC;CACrE,IAAM,IAAa,EAAM,QAAQ,MAAuB,MAAQ,QAAQ,IAAM,CAAC;CAC/E,IAAI,EAAW,WAAW,GAAG,OAAO;CACpC,IAAM,IAAW,KAAK,IAAI,GAAG,CAAU;CAEvC,OADI,IAAW,IAAU,OAClB,IAAW;AACtB;AAwBA,SAAgB,EAAuB,GAAiD;CACpF,IAAM,IAAY,EAAO,MAAM,MAAU,EAAM,WAAW,CAAC;CAC3D,IAAI,MAAc,KAAA,GAAW,OAAO;CACpC,IAAM,IAAa,EAAU,QAAQ,MAAuB,MAAQ,QAAQ,IAAM,CAAC;CACnF,IAAI,EAAW,WAAW,GAAG,OAAO;CACpC,IAAM,IAAW,KAAK,IAAI,GAAG,CAAU,GAEjC,IADa,EAAO,MAAM,MAAU,EAAM,WAAW,CAC1C,CAAA,GAAa,IACxB,IAAQ,OAAO,KAAa,YAAY,IAAW,IAAI,IAAW,IAClE,IAAU,IAAW,IAAI;CAC/B,OAAO,IAAU,IAAI,IAAU;AACnC;AAUA,SAAgB,EAAyB,GAAqC;CAC1E,IAAM,IAAO,EAAM,EAAM,SAAS;CAElC,OADI,KAAS,QAA8B,IAAO,IAAU,OACrD;AACX;AAuBA,SAAgB,EAAiB,GAA6D;CAC1F,IAAM,IAAQ,EAAQ,eAAe,KAAA,IAAY,OAAO,EAAiB,EAAQ,UAAU,GACrF,IAAY,EAAQ;CAQ1B,OAPI,MAAU,OAAa,KAAa,EAAQ,YAC5C,MAAc,KAAA,MAAc,EAAU,OAAO,EAAM,MAAM,EAAU,OAAO,EAAM,OAChF,QAAQ,KACJ,yCAAyC,EAAM,GAAG,GAAG,EAAM,GAAG,iCAChC,EAAU,GAAG,GAAG,EAAU,GAAG,mCAC/D,GAEG;AACX"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
function e(e){let t=0,n=0;for(;e.pos<e.end;){let r=e.bytes[e.pos];if(e.pos+=1,t+=(r&127)*2**n,!(r&128))return t;if(n+=7,n>63)return null}return null}function t(t,n){switch(n){case 0:return e(t)!==null;case 1:return t.pos+=8,t.pos<=t.end;case 2:{let n=e(t);return n!==null&&(t.pos+=n,t.pos<=t.end)}case 5:return t.pos+=4,t.pos<=t.end;default:return!1}}function n(t){let
|
|
2
|
-
`:t===`r`?`\r`:t===`t`?` `:t)}exports.modelNames=
|
|
1
|
+
function e(e){let t=0,n=0;for(;e.pos<e.end;){let r=e.bytes[e.pos];if(e.pos+=1,t+=(r&127)*2**n,!(r&128))return t;if(n+=7,n>63)return null}return null}function t(t,n){switch(n){case 0:return e(t)!==null;case 1:return t.pos+=8,t.pos<=t.end;case 2:{let n=e(t);return n!==null&&(t.pos+=n,t.pos<=t.end)}case 5:return t.pos+=4,t.pos<=t.end;default:return!1}}function n(t,n=1048576){let r=e(t);if(r===null||r>n)return null;let i=t.pos,a=i+r;return a>t.end?null:(t.pos=a,{start:i,end:a})}function r(r,i,a){let o={bytes:r,end:a,pos:i},s=new TextDecoder(`utf-8`,{fatal:!1}),c=null,l=null;for(;o.pos<a;){let i=e(o);if(i===null)return null;let a=i>>>3,u=i&7;if(u===2&&(a===1||a===2)){let e=n(o);if(e===null)return null;let t=s.decode(r.subarray(e.start,e.end));a===1?c=t:l=t;continue}if(!t(o,u))return null}return c===null||l===null?null:[c,l]}function i(i){let a=i instanceof Uint8Array?i:new Uint8Array(i),o={bytes:a,end:a.length,pos:0},s={};for(;o.pos<o.end;){let i=e(o);if(i===null)break;let c=i>>>3,l=i&7;if(c===14&&l===2){let e=n(o);if(e===null)break;let t=r(a,e.start,e.end);t&&(s[t[0]]=t[1]);continue}if(!t(o,l))break}return s}function a(n,r,i){let a={bytes:n,end:i,pos:r};for(;a.pos<a.end;){let n=e(a);if(n===null)return null;let r=n>>>3,i=n&7;if(r===1&&i===0)return e(a);if(!t(a,i))return null}return null}function o(r,i,o){let s={bytes:r,end:o,pos:i};for(;s.pos<s.end;){let i=e(s);if(i===null)return null;let o=i>>>3,c=i&7;if(o===1&&c===2){let e=n(s);return e===null?null:a(r,e.start,e.end)}if(!t(s,c))return null}return null}function s(r,i,a){let s={bytes:r,end:a,pos:i},c=null,l=null;for(;s.pos<s.end;){let i=e(s);if(i===null)return null;let a=i>>>3,u=i&7;if(u===2){let e=n(s);if(e===null)return null;a===1?c=new TextDecoder(`utf-8`,{fatal:!1}).decode(r.subarray(e.start,e.end)):a===2&&(l=o(r,e.start,e.end));continue}if(!t(s,u))return null}return c===null||l===null?null:[c,l]}function c(r){let i=r instanceof Uint8Array?r:new Uint8Array(r),a={bytes:i,end:i.length,pos:0},o={};for(;a.pos<a.end;){let r=e(a);if(r===null)break;let c=r>>>3,l=r&7;if(c===7&&l===2){let r=n(a,i.length);if(r===null)break;let c={bytes:i,end:r.end,pos:r.start};for(;c.pos<c.end;){let r=e(c);if(r===null)break;let a=r>>>3,l=r&7;if(a===11&&l===2){let e=n(c);if(e===null)break;let t=s(i,e.start,e.end);t&&(o[t[0]]=t[1]);continue}if(!t(c,l))break}continue}if(!t(a,l))break}return o}function l(e){return u(e?.names)}function u(e){let t=e?.trim();if(!t||!t.startsWith(`{`)||!t.endsWith(`}`))return null;let n=t.slice(1,-1).trim();if(!n)return null;let r=new Map,i=/(-?\d+)\s*:\s*(?:'((?:[^'\\]|\\.)*)'|"((?:[^"\\]|\\.)*)")/g,a=0;for(let e of n.matchAll(i)){let t=Number(e[1]),n=e[2]??e[3];if(!Number.isInteger(t)||n===void 0)return null;r.set(t,d(n)),a+=e[0].length}if(r.size===0||n.length-a>r.size*3)return null;let o=[];for(let e=0;e<r.size;e+=1){let t=r.get(e);if(t===void 0)return null;o.push(t)}return o}function d(e){return e.replace(/\\(.)/g,(e,t)=>t===`n`?`
|
|
2
|
+
`:t===`r`?`\r`:t===`t`?` `:t)}exports.modelNames=l,exports.parseNames=u,exports.readModelInputTypes=c,exports.readModelMetadata=i;
|
|
3
3
|
//# sourceMappingURL=metadata.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.cjs","names":[],"sources":["../../../src/vision/core/metadata.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Read the metadata an exporter baked into a `.onnx` file.\n *\n * `onnxruntime-web` exposes input/output metadata but **not** the model's\n * custom metadata map, which is where Ultralytics writes `names`, `task` and\n * `imgsz`. The Python SDK gets it for free from\n * `InferenceSession.get_modelmeta().custom_metadata_map`; in the browser the\n * only way to the same information is to read it out of the file, so this\n * module walks just enough of the ModelProto wire format to collect\n * `metadata_props`.\n *\n * It never throws and never allocates unbounded: a truncated, hostile or\n * simply unexpected file yields an empty map, and every caller treats that as\n * \"the model says nothing\", falling back to what it was given.\n */\n\n/** Field number of `metadata_props` in `ModelProto` (repeated StringStringEntryProto). */\nconst MODEL_METADATA_PROPS_FIELD = 14;\n\n/** Field numbers of `key` and `value` in `StringStringEntryProto`. */\nconst ENTRY_KEY_FIELD = 1;\nconst ENTRY_VALUE_FIELD = 2;\n\n/** Protobuf wire types this reader understands. */\nconst WIRE_VARINT = 0;\nconst WIRE_FIXED64 = 1;\nconst WIRE_LENGTH_DELIMITED = 2;\nconst WIRE_FIXED32 = 5;\n\n/**\n * Hard ceiling on a single length-delimited field, as a guard against a corrupt\n * length turning into a huge slice. Model metadata values are strings — a class\n * name map for thousands of classes still fits well inside this.\n */\nconst MAX_FIELD_BYTES = 1 << 20;\n\n/** A cursor over a byte range, tracking its own position. */\ninterface Cursor {\n readonly bytes: Uint8Array;\n readonly end: number;\n pos: number;\n}\n\n/**\n * Read a base-128 varint.\n *\n * @param cursor Cursor to advance.\n * @returns The value, or `null` when the varint is truncated or overlong\n * (beyond the 64-bit range protobuf allows).\n */\nfunction readVarint(cursor: Cursor): number | null {\n let result = 0;\n let shift = 0;\n while (cursor.pos < cursor.end) {\n const byte = cursor.bytes[cursor.pos]!;\n cursor.pos += 1;\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) return result;\n shift += 7;\n if (shift > 63) return null;\n }\n return null;\n}\n\n/**\n * Skip a field whose contents are not needed.\n *\n * @param cursor Cursor to advance past the field's payload.\n * @param wireType Wire type read from the field's tag.\n * @returns `true` when the field was skipped, `false` when the stream is\n * unreadable from here (unknown wire type or truncated payload).\n */\nfunction skipField(cursor: Cursor, wireType: number): boolean {\n switch (wireType) {\n case WIRE_VARINT:\n return readVarint(cursor) !== null;\n case WIRE_FIXED64:\n cursor.pos += 8;\n return cursor.pos <= cursor.end;\n case WIRE_LENGTH_DELIMITED: {\n const length = readVarint(cursor);\n if (length === null) return false;\n cursor.pos += length;\n return cursor.pos <= cursor.end;\n }\n case WIRE_FIXED32:\n cursor.pos += 4;\n return cursor.pos <= cursor.end;\n default:\n return false;\n }\n}\n\n/**\n * Read a length-delimited payload as a byte range.\n *\n * @param cursor Cursor to advance past the payload.\n * @returns Start and end offsets of the payload, or `null` when the length is\n * truncated, overruns the buffer, or exceeds {@link MAX_FIELD_BYTES}.\n */\nfunction readLengthDelimited(cursor: Cursor): { start: number; end: number } | null {\n const length = readVarint(cursor);\n if (length === null || length > MAX_FIELD_BYTES) return null;\n const start = cursor.pos;\n const end = start + length;\n if (end > cursor.end) return null;\n cursor.pos = end;\n return { start, end };\n}\n\n/**\n * Decode one `StringStringEntryProto` into a key/value pair.\n *\n * @param bytes The model buffer.\n * @param start Offset the entry's payload starts at.\n * @param end Offset the entry's payload ends at.\n * @returns The pair, or `null` when either half is missing or undecodable.\n */\nfunction readEntry(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, string] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let key: string | null = null;\n let value: string | null = null;\n\n while (cursor.pos < end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (\n wireType === WIRE_LENGTH_DELIMITED &&\n (field === ENTRY_KEY_FIELD || field === ENTRY_VALUE_FIELD)\n ) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n const text = decoder.decode(bytes.subarray(range.start, range.end));\n if (field === ENTRY_KEY_FIELD) key = text;\n else value = text;\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n\n if (key === null || value === null) return null;\n return [key, value];\n}\n\n/**\n * Collect a model's custom metadata map straight out of its bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Key/value metadata — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export — or an empty object when the file carries none or\n * cannot be walked.\n */\nexport function readModelMetadata(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, string>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const metadata: Record<string, string> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_METADATA_PROPS_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) break;\n const entry = readEntry(bytes, range.start, range.end);\n if (entry) metadata[entry[0]] = entry[1];\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return metadata;\n}\n\n/**\n * Read the class names an export baked into the model metadata.\n *\n * Ultralytics writes `names` as the Python `repr` of a `dict[int, str]` — e.g.\n * `\"{0: 'deworm', 1: 'not_deworm'}\"`. The value is parsed structurally (never\n * evaluated), and anything unparseable, non-`dict`, or not keyed by contiguous\n * integers from zero is rejected whole rather than half-applied: a partial name\n * map would silently mislabel predictions.\n *\n * @param metadata A model's custom metadata map.\n * @returns Class names in class-id order, or `null` when the model carries no\n * usable `names` entry.\n */\nexport function modelNames(\n metadata: Readonly<Record<string, string>> | undefined,\n): readonly string[] | null {\n return parseNames(metadata?.names);\n}\n\n/**\n * Parse a `repr`-encoded `dict[int, str]` class map.\n *\n * Split out of {@link modelNames} because the same encoding is reused by a\n * fused pipeline, which carries one class map per stage and therefore cannot\n * store both under the single `names` key Ultralytics uses.\n *\n * @param encoded The encoded map — e.g. `\"{0: 'deworm', 1: 'not_deworm'}\"`.\n * @returns Class names in class-id order, or `null` when the value is missing,\n * unparseable, not a `dict`, or not keyed by contiguous integers from zero.\n */\nexport function parseNames(encoded: string | undefined): readonly string[] | null {\n const raw = encoded?.trim();\n if (!raw || !raw.startsWith(\"{\") || !raw.endsWith(\"}\")) return null;\n\n const body = raw.slice(1, -1).trim();\n if (!body) return null;\n\n const names = new Map<number, string>();\n const entryPattern = /(-?\\d+)\\s*:\\s*(?:'((?:[^'\\\\]|\\\\.)*)'|\"((?:[^\"\\\\]|\\\\.)*)\")/g;\n let consumed = 0;\n for (const match of body.matchAll(entryPattern)) {\n const id = Number(match[1]);\n const text = match[2] ?? match[3];\n if (!Number.isInteger(id) || text === undefined) return null;\n names.set(id, unescapeQuoted(text));\n consumed += match[0].length;\n }\n if (names.size === 0) return null;\n\n const separators = body.length - consumed;\n if (separators > names.size * 3) return null;\n\n const ordered: string[] = [];\n for (let id = 0; id < names.size; id += 1) {\n const name = names.get(id);\n if (name === undefined) return null;\n ordered.push(name);\n }\n return ordered;\n}\n\n/**\n * Resolve the backslash escapes Python's `repr` emits inside a quoted string.\n *\n * @param text The quoted string's contents, escapes intact.\n * @returns The same text with `\\\\`, `\\'`, `\\\"`, `\\n`, `\\r` and `\\t` resolved.\n */\nfunction unescapeQuoted(text: string): string {\n return text.replace(/\\\\(.)/g, (_, char: string) => {\n if (char === \"n\") return \"\\n\";\n if (char === \"r\") return \"\\r\";\n if (char === \"t\") return \"\\t\";\n return char;\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metadata.cjs","names":[],"sources":["../../../src/vision/core/metadata.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Read the metadata an exporter baked into a `.onnx` file.\n *\n * `onnxruntime-web` exposes input/output metadata but **not** the model's\n * custom metadata map, which is where Ultralytics writes `names`, `task` and\n * `imgsz`. The Python SDK gets it for free from\n * `InferenceSession.get_modelmeta().custom_metadata_map`; in the browser the\n * only way to the same information is to read it out of the file, so this\n * module walks just enough of the ModelProto wire format to collect\n * `metadata_props`.\n *\n * It never throws and never allocates unbounded: a truncated, hostile or\n * simply unexpected file yields an empty map, and every caller treats that as\n * \"the model says nothing\", falling back to what it was given.\n */\n\n/** Field number of `metadata_props` in `ModelProto` (repeated StringStringEntryProto). */\nconst MODEL_METADATA_PROPS_FIELD = 14;\n\n/** Field number of `graph` in `ModelProto` (GraphProto). */\nconst MODEL_GRAPH_FIELD = 7;\n\n/** Field number of `input` in `GraphProto` (repeated ValueInfoProto). */\nconst GRAPH_INPUT_FIELD = 11;\n\n/** Field numbers of `name` and `type` in `ValueInfoProto`. */\nconst VALUE_INFO_NAME_FIELD = 1;\nconst VALUE_INFO_TYPE_FIELD = 2;\n\n/** Field number of `tensor_type` in `TypeProto` (TypeProto.Tensor). */\nconst TYPE_TENSOR_FIELD = 1;\n\n/** Field number of `elem_type` in `TypeProto.Tensor` (a `TensorProto.DataType`). */\nconst TENSOR_ELEM_TYPE_FIELD = 1;\n\n/** Field numbers of `key` and `value` in `StringStringEntryProto`. */\nconst ENTRY_KEY_FIELD = 1;\nconst ENTRY_VALUE_FIELD = 2;\n\n/** Protobuf wire types this reader understands. */\nconst WIRE_VARINT = 0;\nconst WIRE_FIXED64 = 1;\nconst WIRE_LENGTH_DELIMITED = 2;\nconst WIRE_FIXED32 = 5;\n\n/**\n * Hard ceiling on a single length-delimited field, as a guard against a corrupt\n * length turning into a huge slice. Model metadata values are strings — a class\n * name map for thousands of classes still fits well inside this.\n *\n * It applies to leaf fields being read *out* of the file, not to the messages\n * walked *through* to reach them. The `graph` of a real export is the file: 21.79\n * MB on a reported YOLO detector. Applying this ceiling there made the reader\n * give up on every model anyone would actually load, and give up silently.\n */\nconst MAX_FIELD_BYTES = 1 << 20;\n\n/** A cursor over a byte range, tracking its own position. */\ninterface Cursor {\n readonly bytes: Uint8Array;\n readonly end: number;\n pos: number;\n}\n\n/**\n * Read a base-128 varint.\n *\n * @param cursor Cursor to advance.\n * @returns The value, or `null` when the varint is truncated or overlong\n * (beyond the 64-bit range protobuf allows).\n */\nfunction readVarint(cursor: Cursor): number | null {\n let result = 0;\n let shift = 0;\n while (cursor.pos < cursor.end) {\n const byte = cursor.bytes[cursor.pos]!;\n cursor.pos += 1;\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) return result;\n shift += 7;\n if (shift > 63) return null;\n }\n return null;\n}\n\n/**\n * Skip a field whose contents are not needed.\n *\n * @param cursor Cursor to advance past the field's payload.\n * @param wireType Wire type read from the field's tag.\n * @returns `true` when the field was skipped, `false` when the stream is\n * unreadable from here (unknown wire type or truncated payload).\n */\nfunction skipField(cursor: Cursor, wireType: number): boolean {\n switch (wireType) {\n case WIRE_VARINT:\n return readVarint(cursor) !== null;\n case WIRE_FIXED64:\n cursor.pos += 8;\n return cursor.pos <= cursor.end;\n case WIRE_LENGTH_DELIMITED: {\n const length = readVarint(cursor);\n if (length === null) return false;\n cursor.pos += length;\n return cursor.pos <= cursor.end;\n }\n case WIRE_FIXED32:\n cursor.pos += 4;\n return cursor.pos <= cursor.end;\n default:\n return false;\n }\n}\n\n/**\n * Read a length-delimited payload as a byte range.\n *\n * @param cursor Cursor to advance past the payload.\n * @param maxBytes Largest payload to accept, defaulting to\n * {@link MAX_FIELD_BYTES}. Pass the buffer length when descending into a\n * message whose size is the file's size rather than a leaf value's.\n * @returns Start and end offsets of the payload, or `null` when the length is\n * truncated, overruns the buffer, or exceeds `maxBytes`.\n */\nfunction readLengthDelimited(\n cursor: Cursor,\n maxBytes: number = MAX_FIELD_BYTES,\n): { start: number; end: number } | null {\n const length = readVarint(cursor);\n if (length === null || length > maxBytes) return null;\n const start = cursor.pos;\n const end = start + length;\n if (end > cursor.end) return null;\n cursor.pos = end;\n return { start, end };\n}\n\n/**\n * Decode one `StringStringEntryProto` into a key/value pair.\n *\n * @param bytes The model buffer.\n * @param start Offset the entry's payload starts at.\n * @param end Offset the entry's payload ends at.\n * @returns The pair, or `null` when either half is missing or undecodable.\n */\nfunction readEntry(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, string] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let key: string | null = null;\n let value: string | null = null;\n\n while (cursor.pos < end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (\n wireType === WIRE_LENGTH_DELIMITED &&\n (field === ENTRY_KEY_FIELD || field === ENTRY_VALUE_FIELD)\n ) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n const text = decoder.decode(bytes.subarray(range.start, range.end));\n if (field === ENTRY_KEY_FIELD) key = text;\n else value = text;\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n\n if (key === null || value === null) return null;\n return [key, value];\n}\n\n/**\n * Collect a model's custom metadata map straight out of its bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Key/value metadata — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export — or an empty object when the file carries none or\n * cannot be walked.\n */\nexport function readModelMetadata(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, string>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const metadata: Record<string, string> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_METADATA_PROPS_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) break;\n const entry = readEntry(bytes, range.start, range.end);\n if (entry) metadata[entry[0]] = entry[1];\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return metadata;\n}\n\n/**\n * Read the element type of a `TypeProto.Tensor` message.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The `TensorProto.DataType` value, or `null` when the message\n * carries none or cannot be walked.\n */\nfunction readTensorElemType(bytes: Uint8Array, start: number, end: number): number | null {\n const cursor: Cursor = { bytes, end, pos: start };\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === TENSOR_ELEM_TYPE_FIELD && wireType === WIRE_VARINT) {\n return readVarint(cursor);\n }\n if (!skipField(cursor, wireType)) return null;\n }\n return null;\n}\n\n/**\n * Read the element type out of a `TypeProto`, which wraps the tensor type.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The `TensorProto.DataType` value, or `null` for a non-tensor type\n * (sequence, map, optional) or an unreadable message.\n */\nfunction readTypeElemType(bytes: Uint8Array, start: number, end: number): number | null {\n const cursor: Cursor = { bytes, end, pos: start };\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === TYPE_TENSOR_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n return readTensorElemType(bytes, range.start, range.end);\n }\n if (!skipField(cursor, wireType)) return null;\n }\n return null;\n}\n\n/**\n * Read one `ValueInfoProto` into a name/element-type pair.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The pair, or `null` when either half is missing or unreadable.\n */\nfunction readValueInfo(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, number] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n let name: string | null = null;\n let elemType: number | null = null;\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n if (field === VALUE_INFO_NAME_FIELD) {\n name = new TextDecoder(\"utf-8\", { fatal: false }).decode(\n bytes.subarray(range.start, range.end),\n );\n } else if (field === VALUE_INFO_TYPE_FIELD) {\n elemType = readTypeElemType(bytes, range.start, range.end);\n }\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n if (name === null || elemType === null) return null;\n return [name, elemType];\n}\n\n/**\n * Read the element type each graph input declares.\n *\n * `onnxruntime-web` does not expose this. `session.inputMetadata` is\n * `undefined` on 1.20.1 — the same version where `declaredShapesFrom` comes\n * back empty — so the declared types have to come from the file, which the SDK\n * already downloads and walks for {@link readModelMetadata}. Same bytes, one\n * more pass, no extra request.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → `TensorProto.DataType` value. An empty object when the\n * file carries no readable graph, which every caller treats as \"assume\n * float32\" — the behaviour before any of this existed.\n */\nexport function readModelInputTypes(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, number>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const types: Record<string, number> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_GRAPH_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const graph = readLengthDelimited(cursor, bytes.length);\n if (graph === null) break;\n const inner: Cursor = { bytes, end: graph.end, pos: graph.start };\n while (inner.pos < inner.end) {\n const innerTag = readVarint(inner);\n if (innerTag === null) break;\n const innerField = innerTag >>> 3;\n const innerWire = innerTag & 0x07;\n if (innerField === GRAPH_INPUT_FIELD && innerWire === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(inner);\n if (range === null) break;\n const info = readValueInfo(bytes, range.start, range.end);\n if (info) types[info[0]] = info[1];\n continue;\n }\n if (!skipField(inner, innerWire)) break;\n }\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return types;\n}\n\n/**\n * Read the class names an export baked into the model metadata.\n *\n * Ultralytics writes `names` as the Python `repr` of a `dict[int, str]` — e.g.\n * `\"{0: 'deworm', 1: 'not_deworm'}\"`. The value is parsed structurally (never\n * evaluated), and anything unparseable, non-`dict`, or not keyed by contiguous\n * integers from zero is rejected whole rather than half-applied: a partial name\n * map would silently mislabel predictions.\n *\n * @param metadata A model's custom metadata map.\n * @returns Class names in class-id order, or `null` when the model carries no\n * usable `names` entry.\n */\nexport function modelNames(\n metadata: Readonly<Record<string, string>> | undefined,\n): readonly string[] | null {\n return parseNames(metadata?.names);\n}\n\n/**\n * Parse a `repr`-encoded `dict[int, str]` class map.\n *\n * Split out of {@link modelNames} because the same encoding is reused by a\n * fused pipeline, which carries one class map per stage and therefore cannot\n * store both under the single `names` key Ultralytics uses.\n *\n * @param encoded The encoded map — e.g. `\"{0: 'deworm', 1: 'not_deworm'}\"`.\n * @returns Class names in class-id order, or `null` when the value is missing,\n * unparseable, not a `dict`, or not keyed by contiguous integers from zero.\n */\nexport function parseNames(encoded: string | undefined): readonly string[] | null {\n const raw = encoded?.trim();\n if (!raw || !raw.startsWith(\"{\") || !raw.endsWith(\"}\")) return null;\n\n const body = raw.slice(1, -1).trim();\n if (!body) return null;\n\n const names = new Map<number, string>();\n const entryPattern = /(-?\\d+)\\s*:\\s*(?:'((?:[^'\\\\]|\\\\.)*)'|\"((?:[^\"\\\\]|\\\\.)*)\")/g;\n let consumed = 0;\n for (const match of body.matchAll(entryPattern)) {\n const id = Number(match[1]);\n const text = match[2] ?? match[3];\n if (!Number.isInteger(id) || text === undefined) return null;\n names.set(id, unescapeQuoted(text));\n consumed += match[0].length;\n }\n if (names.size === 0) return null;\n\n const separators = body.length - consumed;\n if (separators > names.size * 3) return null;\n\n const ordered: string[] = [];\n for (let id = 0; id < names.size; id += 1) {\n const name = names.get(id);\n if (name === undefined) return null;\n ordered.push(name);\n }\n return ordered;\n}\n\n/**\n * Resolve the backslash escapes Python's `repr` emits inside a quoted string.\n *\n * @param text The quoted string's contents, escapes intact.\n * @returns The same text with `\\\\`, `\\'`, `\\\"`, `\\n`, `\\r` and `\\t` resolved.\n */\nfunction unescapeQuoted(text: string): string {\n return text.replace(/\\\\(.)/g, (_, char: string) => {\n if (char === \"n\") return \"\\n\";\n if (char === \"r\") return \"\\r\";\n if (char === \"t\") return \"\\t\";\n return char;\n });\n}\n"],"mappings":"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"}
|
|
@@ -19,13 +19,13 @@ function t(t, n) {
|
|
|
19
19
|
default: return !1;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
function n(t) {
|
|
23
|
-
let
|
|
24
|
-
if (
|
|
25
|
-
let
|
|
26
|
-
return
|
|
27
|
-
start:
|
|
28
|
-
end:
|
|
22
|
+
function n(t, n = 1048576) {
|
|
23
|
+
let r = e(t);
|
|
24
|
+
if (r === null || r > n) return null;
|
|
25
|
+
let i = t.pos, a = i + r;
|
|
26
|
+
return a > t.end ? null : (t.pos = a, {
|
|
27
|
+
start: i,
|
|
28
|
+
end: a
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
function r(r, i, a) {
|
|
@@ -70,10 +70,100 @@ function i(i) {
|
|
|
70
70
|
}
|
|
71
71
|
return s;
|
|
72
72
|
}
|
|
73
|
-
function a(
|
|
74
|
-
|
|
73
|
+
function a(n, r, i) {
|
|
74
|
+
let a = {
|
|
75
|
+
bytes: n,
|
|
76
|
+
end: i,
|
|
77
|
+
pos: r
|
|
78
|
+
};
|
|
79
|
+
for (; a.pos < a.end;) {
|
|
80
|
+
let n = e(a);
|
|
81
|
+
if (n === null) return null;
|
|
82
|
+
let r = n >>> 3, i = n & 7;
|
|
83
|
+
if (r === 1 && i === 0) return e(a);
|
|
84
|
+
if (!t(a, i)) return null;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function o(r, i, o) {
|
|
89
|
+
let s = {
|
|
90
|
+
bytes: r,
|
|
91
|
+
end: o,
|
|
92
|
+
pos: i
|
|
93
|
+
};
|
|
94
|
+
for (; s.pos < s.end;) {
|
|
95
|
+
let i = e(s);
|
|
96
|
+
if (i === null) return null;
|
|
97
|
+
let o = i >>> 3, c = i & 7;
|
|
98
|
+
if (o === 1 && c === 2) {
|
|
99
|
+
let e = n(s);
|
|
100
|
+
return e === null ? null : a(r, e.start, e.end);
|
|
101
|
+
}
|
|
102
|
+
if (!t(s, c)) return null;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
function s(r, i, a) {
|
|
107
|
+
let s = {
|
|
108
|
+
bytes: r,
|
|
109
|
+
end: a,
|
|
110
|
+
pos: i
|
|
111
|
+
}, c = null, l = null;
|
|
112
|
+
for (; s.pos < s.end;) {
|
|
113
|
+
let i = e(s);
|
|
114
|
+
if (i === null) return null;
|
|
115
|
+
let a = i >>> 3, u = i & 7;
|
|
116
|
+
if (u === 2) {
|
|
117
|
+
let e = n(s);
|
|
118
|
+
if (e === null) return null;
|
|
119
|
+
a === 1 ? c = new TextDecoder("utf-8", { fatal: !1 }).decode(r.subarray(e.start, e.end)) : a === 2 && (l = o(r, e.start, e.end));
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (!t(s, u)) return null;
|
|
123
|
+
}
|
|
124
|
+
return c === null || l === null ? null : [c, l];
|
|
125
|
+
}
|
|
126
|
+
function c(r) {
|
|
127
|
+
let i = r instanceof Uint8Array ? r : new Uint8Array(r), a = {
|
|
128
|
+
bytes: i,
|
|
129
|
+
end: i.length,
|
|
130
|
+
pos: 0
|
|
131
|
+
}, o = {};
|
|
132
|
+
for (; a.pos < a.end;) {
|
|
133
|
+
let r = e(a);
|
|
134
|
+
if (r === null) break;
|
|
135
|
+
let c = r >>> 3, l = r & 7;
|
|
136
|
+
if (c === 7 && l === 2) {
|
|
137
|
+
let r = n(a, i.length);
|
|
138
|
+
if (r === null) break;
|
|
139
|
+
let c = {
|
|
140
|
+
bytes: i,
|
|
141
|
+
end: r.end,
|
|
142
|
+
pos: r.start
|
|
143
|
+
};
|
|
144
|
+
for (; c.pos < c.end;) {
|
|
145
|
+
let r = e(c);
|
|
146
|
+
if (r === null) break;
|
|
147
|
+
let a = r >>> 3, l = r & 7;
|
|
148
|
+
if (a === 11 && l === 2) {
|
|
149
|
+
let e = n(c);
|
|
150
|
+
if (e === null) break;
|
|
151
|
+
let t = s(i, e.start, e.end);
|
|
152
|
+
t && (o[t[0]] = t[1]);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (!t(c, l)) break;
|
|
156
|
+
}
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!t(a, l)) break;
|
|
160
|
+
}
|
|
161
|
+
return o;
|
|
162
|
+
}
|
|
163
|
+
function l(e) {
|
|
164
|
+
return u(e?.names);
|
|
75
165
|
}
|
|
76
|
-
function
|
|
166
|
+
function u(e) {
|
|
77
167
|
let t = e?.trim();
|
|
78
168
|
if (!t || !t.startsWith("{") || !t.endsWith("}")) return null;
|
|
79
169
|
let n = t.slice(1, -1).trim();
|
|
@@ -82,7 +172,7 @@ function o(e) {
|
|
|
82
172
|
for (let e of n.matchAll(i)) {
|
|
83
173
|
let t = Number(e[1]), n = e[2] ?? e[3];
|
|
84
174
|
if (!Number.isInteger(t) || n === void 0) return null;
|
|
85
|
-
r.set(t,
|
|
175
|
+
r.set(t, d(n)), a += e[0].length;
|
|
86
176
|
}
|
|
87
177
|
if (r.size === 0 || n.length - a > r.size * 3) return null;
|
|
88
178
|
let o = [];
|
|
@@ -93,10 +183,10 @@ function o(e) {
|
|
|
93
183
|
}
|
|
94
184
|
return o;
|
|
95
185
|
}
|
|
96
|
-
function
|
|
186
|
+
function d(e) {
|
|
97
187
|
return e.replace(/\\(.)/g, (e, t) => t === "n" ? "\n" : t === "r" ? "\r" : t === "t" ? " " : t);
|
|
98
188
|
}
|
|
99
189
|
//#endregion
|
|
100
|
-
export {
|
|
190
|
+
export { l as modelNames, u as parseNames, c as readModelInputTypes, i as readModelMetadata };
|
|
101
191
|
|
|
102
192
|
//# sourceMappingURL=metadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","names":[],"sources":["../../../src/vision/core/metadata.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Read the metadata an exporter baked into a `.onnx` file.\n *\n * `onnxruntime-web` exposes input/output metadata but **not** the model's\n * custom metadata map, which is where Ultralytics writes `names`, `task` and\n * `imgsz`. The Python SDK gets it for free from\n * `InferenceSession.get_modelmeta().custom_metadata_map`; in the browser the\n * only way to the same information is to read it out of the file, so this\n * module walks just enough of the ModelProto wire format to collect\n * `metadata_props`.\n *\n * It never throws and never allocates unbounded: a truncated, hostile or\n * simply unexpected file yields an empty map, and every caller treats that as\n * \"the model says nothing\", falling back to what it was given.\n */\n\n/** Field number of `metadata_props` in `ModelProto` (repeated StringStringEntryProto). */\nconst MODEL_METADATA_PROPS_FIELD = 14;\n\n/** Field numbers of `key` and `value` in `StringStringEntryProto`. */\nconst ENTRY_KEY_FIELD = 1;\nconst ENTRY_VALUE_FIELD = 2;\n\n/** Protobuf wire types this reader understands. */\nconst WIRE_VARINT = 0;\nconst WIRE_FIXED64 = 1;\nconst WIRE_LENGTH_DELIMITED = 2;\nconst WIRE_FIXED32 = 5;\n\n/**\n * Hard ceiling on a single length-delimited field, as a guard against a corrupt\n * length turning into a huge slice. Model metadata values are strings — a class\n * name map for thousands of classes still fits well inside this.\n */\nconst MAX_FIELD_BYTES = 1 << 20;\n\n/** A cursor over a byte range, tracking its own position. */\ninterface Cursor {\n readonly bytes: Uint8Array;\n readonly end: number;\n pos: number;\n}\n\n/**\n * Read a base-128 varint.\n *\n * @param cursor Cursor to advance.\n * @returns The value, or `null` when the varint is truncated or overlong\n * (beyond the 64-bit range protobuf allows).\n */\nfunction readVarint(cursor: Cursor): number | null {\n let result = 0;\n let shift = 0;\n while (cursor.pos < cursor.end) {\n const byte = cursor.bytes[cursor.pos]!;\n cursor.pos += 1;\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) return result;\n shift += 7;\n if (shift > 63) return null;\n }\n return null;\n}\n\n/**\n * Skip a field whose contents are not needed.\n *\n * @param cursor Cursor to advance past the field's payload.\n * @param wireType Wire type read from the field's tag.\n * @returns `true` when the field was skipped, `false` when the stream is\n * unreadable from here (unknown wire type or truncated payload).\n */\nfunction skipField(cursor: Cursor, wireType: number): boolean {\n switch (wireType) {\n case WIRE_VARINT:\n return readVarint(cursor) !== null;\n case WIRE_FIXED64:\n cursor.pos += 8;\n return cursor.pos <= cursor.end;\n case WIRE_LENGTH_DELIMITED: {\n const length = readVarint(cursor);\n if (length === null) return false;\n cursor.pos += length;\n return cursor.pos <= cursor.end;\n }\n case WIRE_FIXED32:\n cursor.pos += 4;\n return cursor.pos <= cursor.end;\n default:\n return false;\n }\n}\n\n/**\n * Read a length-delimited payload as a byte range.\n *\n * @param cursor Cursor to advance past the payload.\n * @returns Start and end offsets of the payload, or `null` when the length is\n * truncated, overruns the buffer, or exceeds {@link MAX_FIELD_BYTES}.\n */\nfunction readLengthDelimited(cursor: Cursor): { start: number; end: number } | null {\n const length = readVarint(cursor);\n if (length === null || length > MAX_FIELD_BYTES) return null;\n const start = cursor.pos;\n const end = start + length;\n if (end > cursor.end) return null;\n cursor.pos = end;\n return { start, end };\n}\n\n/**\n * Decode one `StringStringEntryProto` into a key/value pair.\n *\n * @param bytes The model buffer.\n * @param start Offset the entry's payload starts at.\n * @param end Offset the entry's payload ends at.\n * @returns The pair, or `null` when either half is missing or undecodable.\n */\nfunction readEntry(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, string] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let key: string | null = null;\n let value: string | null = null;\n\n while (cursor.pos < end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (\n wireType === WIRE_LENGTH_DELIMITED &&\n (field === ENTRY_KEY_FIELD || field === ENTRY_VALUE_FIELD)\n ) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n const text = decoder.decode(bytes.subarray(range.start, range.end));\n if (field === ENTRY_KEY_FIELD) key = text;\n else value = text;\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n\n if (key === null || value === null) return null;\n return [key, value];\n}\n\n/**\n * Collect a model's custom metadata map straight out of its bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Key/value metadata — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export — or an empty object when the file carries none or\n * cannot be walked.\n */\nexport function readModelMetadata(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, string>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const metadata: Record<string, string> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_METADATA_PROPS_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) break;\n const entry = readEntry(bytes, range.start, range.end);\n if (entry) metadata[entry[0]] = entry[1];\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return metadata;\n}\n\n/**\n * Read the class names an export baked into the model metadata.\n *\n * Ultralytics writes `names` as the Python `repr` of a `dict[int, str]` — e.g.\n * `\"{0: 'deworm', 1: 'not_deworm'}\"`. The value is parsed structurally (never\n * evaluated), and anything unparseable, non-`dict`, or not keyed by contiguous\n * integers from zero is rejected whole rather than half-applied: a partial name\n * map would silently mislabel predictions.\n *\n * @param metadata A model's custom metadata map.\n * @returns Class names in class-id order, or `null` when the model carries no\n * usable `names` entry.\n */\nexport function modelNames(\n metadata: Readonly<Record<string, string>> | undefined,\n): readonly string[] | null {\n return parseNames(metadata?.names);\n}\n\n/**\n * Parse a `repr`-encoded `dict[int, str]` class map.\n *\n * Split out of {@link modelNames} because the same encoding is reused by a\n * fused pipeline, which carries one class map per stage and therefore cannot\n * store both under the single `names` key Ultralytics uses.\n *\n * @param encoded The encoded map — e.g. `\"{0: 'deworm', 1: 'not_deworm'}\"`.\n * @returns Class names in class-id order, or `null` when the value is missing,\n * unparseable, not a `dict`, or not keyed by contiguous integers from zero.\n */\nexport function parseNames(encoded: string | undefined): readonly string[] | null {\n const raw = encoded?.trim();\n if (!raw || !raw.startsWith(\"{\") || !raw.endsWith(\"}\")) return null;\n\n const body = raw.slice(1, -1).trim();\n if (!body) return null;\n\n const names = new Map<number, string>();\n const entryPattern = /(-?\\d+)\\s*:\\s*(?:'((?:[^'\\\\]|\\\\.)*)'|\"((?:[^\"\\\\]|\\\\.)*)\")/g;\n let consumed = 0;\n for (const match of body.matchAll(entryPattern)) {\n const id = Number(match[1]);\n const text = match[2] ?? match[3];\n if (!Number.isInteger(id) || text === undefined) return null;\n names.set(id, unescapeQuoted(text));\n consumed += match[0].length;\n }\n if (names.size === 0) return null;\n\n const separators = body.length - consumed;\n if (separators > names.size * 3) return null;\n\n const ordered: string[] = [];\n for (let id = 0; id < names.size; id += 1) {\n const name = names.get(id);\n if (name === undefined) return null;\n ordered.push(name);\n }\n return ordered;\n}\n\n/**\n * Resolve the backslash escapes Python's `repr` emits inside a quoted string.\n *\n * @param text The quoted string's contents, escapes intact.\n * @returns The same text with `\\\\`, `\\'`, `\\\"`, `\\n`, `\\r` and `\\t` resolved.\n */\nfunction unescapeQuoted(text: string): string {\n return text.replace(/\\\\(.)/g, (_, char: string) => {\n if (char === \"n\") return \"\\n\";\n if (char === \"r\") return \"\\r\";\n if (char === \"t\") return \"\\t\";\n return char;\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metadata.js","names":[],"sources":["../../../src/vision/core/metadata.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Read the metadata an exporter baked into a `.onnx` file.\n *\n * `onnxruntime-web` exposes input/output metadata but **not** the model's\n * custom metadata map, which is where Ultralytics writes `names`, `task` and\n * `imgsz`. The Python SDK gets it for free from\n * `InferenceSession.get_modelmeta().custom_metadata_map`; in the browser the\n * only way to the same information is to read it out of the file, so this\n * module walks just enough of the ModelProto wire format to collect\n * `metadata_props`.\n *\n * It never throws and never allocates unbounded: a truncated, hostile or\n * simply unexpected file yields an empty map, and every caller treats that as\n * \"the model says nothing\", falling back to what it was given.\n */\n\n/** Field number of `metadata_props` in `ModelProto` (repeated StringStringEntryProto). */\nconst MODEL_METADATA_PROPS_FIELD = 14;\n\n/** Field number of `graph` in `ModelProto` (GraphProto). */\nconst MODEL_GRAPH_FIELD = 7;\n\n/** Field number of `input` in `GraphProto` (repeated ValueInfoProto). */\nconst GRAPH_INPUT_FIELD = 11;\n\n/** Field numbers of `name` and `type` in `ValueInfoProto`. */\nconst VALUE_INFO_NAME_FIELD = 1;\nconst VALUE_INFO_TYPE_FIELD = 2;\n\n/** Field number of `tensor_type` in `TypeProto` (TypeProto.Tensor). */\nconst TYPE_TENSOR_FIELD = 1;\n\n/** Field number of `elem_type` in `TypeProto.Tensor` (a `TensorProto.DataType`). */\nconst TENSOR_ELEM_TYPE_FIELD = 1;\n\n/** Field numbers of `key` and `value` in `StringStringEntryProto`. */\nconst ENTRY_KEY_FIELD = 1;\nconst ENTRY_VALUE_FIELD = 2;\n\n/** Protobuf wire types this reader understands. */\nconst WIRE_VARINT = 0;\nconst WIRE_FIXED64 = 1;\nconst WIRE_LENGTH_DELIMITED = 2;\nconst WIRE_FIXED32 = 5;\n\n/**\n * Hard ceiling on a single length-delimited field, as a guard against a corrupt\n * length turning into a huge slice. Model metadata values are strings — a class\n * name map for thousands of classes still fits well inside this.\n *\n * It applies to leaf fields being read *out* of the file, not to the messages\n * walked *through* to reach them. The `graph` of a real export is the file: 21.79\n * MB on a reported YOLO detector. Applying this ceiling there made the reader\n * give up on every model anyone would actually load, and give up silently.\n */\nconst MAX_FIELD_BYTES = 1 << 20;\n\n/** A cursor over a byte range, tracking its own position. */\ninterface Cursor {\n readonly bytes: Uint8Array;\n readonly end: number;\n pos: number;\n}\n\n/**\n * Read a base-128 varint.\n *\n * @param cursor Cursor to advance.\n * @returns The value, or `null` when the varint is truncated or overlong\n * (beyond the 64-bit range protobuf allows).\n */\nfunction readVarint(cursor: Cursor): number | null {\n let result = 0;\n let shift = 0;\n while (cursor.pos < cursor.end) {\n const byte = cursor.bytes[cursor.pos]!;\n cursor.pos += 1;\n result += (byte & 0x7f) * 2 ** shift;\n if ((byte & 0x80) === 0) return result;\n shift += 7;\n if (shift > 63) return null;\n }\n return null;\n}\n\n/**\n * Skip a field whose contents are not needed.\n *\n * @param cursor Cursor to advance past the field's payload.\n * @param wireType Wire type read from the field's tag.\n * @returns `true` when the field was skipped, `false` when the stream is\n * unreadable from here (unknown wire type or truncated payload).\n */\nfunction skipField(cursor: Cursor, wireType: number): boolean {\n switch (wireType) {\n case WIRE_VARINT:\n return readVarint(cursor) !== null;\n case WIRE_FIXED64:\n cursor.pos += 8;\n return cursor.pos <= cursor.end;\n case WIRE_LENGTH_DELIMITED: {\n const length = readVarint(cursor);\n if (length === null) return false;\n cursor.pos += length;\n return cursor.pos <= cursor.end;\n }\n case WIRE_FIXED32:\n cursor.pos += 4;\n return cursor.pos <= cursor.end;\n default:\n return false;\n }\n}\n\n/**\n * Read a length-delimited payload as a byte range.\n *\n * @param cursor Cursor to advance past the payload.\n * @param maxBytes Largest payload to accept, defaulting to\n * {@link MAX_FIELD_BYTES}. Pass the buffer length when descending into a\n * message whose size is the file's size rather than a leaf value's.\n * @returns Start and end offsets of the payload, or `null` when the length is\n * truncated, overruns the buffer, or exceeds `maxBytes`.\n */\nfunction readLengthDelimited(\n cursor: Cursor,\n maxBytes: number = MAX_FIELD_BYTES,\n): { start: number; end: number } | null {\n const length = readVarint(cursor);\n if (length === null || length > maxBytes) return null;\n const start = cursor.pos;\n const end = start + length;\n if (end > cursor.end) return null;\n cursor.pos = end;\n return { start, end };\n}\n\n/**\n * Decode one `StringStringEntryProto` into a key/value pair.\n *\n * @param bytes The model buffer.\n * @param start Offset the entry's payload starts at.\n * @param end Offset the entry's payload ends at.\n * @returns The pair, or `null` when either half is missing or undecodable.\n */\nfunction readEntry(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, string] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n const decoder = new TextDecoder(\"utf-8\", { fatal: false });\n let key: string | null = null;\n let value: string | null = null;\n\n while (cursor.pos < end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (\n wireType === WIRE_LENGTH_DELIMITED &&\n (field === ENTRY_KEY_FIELD || field === ENTRY_VALUE_FIELD)\n ) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n const text = decoder.decode(bytes.subarray(range.start, range.end));\n if (field === ENTRY_KEY_FIELD) key = text;\n else value = text;\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n\n if (key === null || value === null) return null;\n return [key, value];\n}\n\n/**\n * Collect a model's custom metadata map straight out of its bytes.\n *\n * @param model The `.onnx` file contents.\n * @returns Key/value metadata — `names`, `task`, `imgsz`, ... for an\n * Ultralytics export — or an empty object when the file carries none or\n * cannot be walked.\n */\nexport function readModelMetadata(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, string>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const metadata: Record<string, string> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_METADATA_PROPS_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) break;\n const entry = readEntry(bytes, range.start, range.end);\n if (entry) metadata[entry[0]] = entry[1];\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return metadata;\n}\n\n/**\n * Read the element type of a `TypeProto.Tensor` message.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The `TensorProto.DataType` value, or `null` when the message\n * carries none or cannot be walked.\n */\nfunction readTensorElemType(bytes: Uint8Array, start: number, end: number): number | null {\n const cursor: Cursor = { bytes, end, pos: start };\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === TENSOR_ELEM_TYPE_FIELD && wireType === WIRE_VARINT) {\n return readVarint(cursor);\n }\n if (!skipField(cursor, wireType)) return null;\n }\n return null;\n}\n\n/**\n * Read the element type out of a `TypeProto`, which wraps the tensor type.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The `TensorProto.DataType` value, or `null` for a non-tensor type\n * (sequence, map, optional) or an unreadable message.\n */\nfunction readTypeElemType(bytes: Uint8Array, start: number, end: number): number | null {\n const cursor: Cursor = { bytes, end, pos: start };\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === TYPE_TENSOR_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n return readTensorElemType(bytes, range.start, range.end);\n }\n if (!skipField(cursor, wireType)) return null;\n }\n return null;\n}\n\n/**\n * Read one `ValueInfoProto` into a name/element-type pair.\n *\n * @param bytes The whole model buffer.\n * @param start Offset of the message's first byte.\n * @param end Offset one past its last byte.\n * @returns The pair, or `null` when either half is missing or unreadable.\n */\nfunction readValueInfo(\n bytes: Uint8Array,\n start: number,\n end: number,\n): readonly [string, number] | null {\n const cursor: Cursor = { bytes, end, pos: start };\n let name: string | null = null;\n let elemType: number | null = null;\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) return null;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (wireType === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(cursor);\n if (range === null) return null;\n if (field === VALUE_INFO_NAME_FIELD) {\n name = new TextDecoder(\"utf-8\", { fatal: false }).decode(\n bytes.subarray(range.start, range.end),\n );\n } else if (field === VALUE_INFO_TYPE_FIELD) {\n elemType = readTypeElemType(bytes, range.start, range.end);\n }\n continue;\n }\n if (!skipField(cursor, wireType)) return null;\n }\n if (name === null || elemType === null) return null;\n return [name, elemType];\n}\n\n/**\n * Read the element type each graph input declares.\n *\n * `onnxruntime-web` does not expose this. `session.inputMetadata` is\n * `undefined` on 1.20.1 — the same version where `declaredShapesFrom` comes\n * back empty — so the declared types have to come from the file, which the SDK\n * already downloads and walks for {@link readModelMetadata}. Same bytes, one\n * more pass, no extra request.\n *\n * @param model The `.onnx` file contents.\n * @returns Input name → `TensorProto.DataType` value. An empty object when the\n * file carries no readable graph, which every caller treats as \"assume\n * float32\" — the behaviour before any of this existed.\n */\nexport function readModelInputTypes(\n model: Uint8Array | ArrayBufferLike,\n): Readonly<Record<string, number>> {\n const bytes = model instanceof Uint8Array ? model : new Uint8Array(model);\n const cursor: Cursor = { bytes, end: bytes.length, pos: 0 };\n const types: Record<string, number> = {};\n\n while (cursor.pos < cursor.end) {\n const tag = readVarint(cursor);\n if (tag === null) break;\n const field = tag >>> 3;\n const wireType = tag & 0x07;\n if (field === MODEL_GRAPH_FIELD && wireType === WIRE_LENGTH_DELIMITED) {\n const graph = readLengthDelimited(cursor, bytes.length);\n if (graph === null) break;\n const inner: Cursor = { bytes, end: graph.end, pos: graph.start };\n while (inner.pos < inner.end) {\n const innerTag = readVarint(inner);\n if (innerTag === null) break;\n const innerField = innerTag >>> 3;\n const innerWire = innerTag & 0x07;\n if (innerField === GRAPH_INPUT_FIELD && innerWire === WIRE_LENGTH_DELIMITED) {\n const range = readLengthDelimited(inner);\n if (range === null) break;\n const info = readValueInfo(bytes, range.start, range.end);\n if (info) types[info[0]] = info[1];\n continue;\n }\n if (!skipField(inner, innerWire)) break;\n }\n continue;\n }\n if (!skipField(cursor, wireType)) break;\n }\n\n return types;\n}\n\n/**\n * Read the class names an export baked into the model metadata.\n *\n * Ultralytics writes `names` as the Python `repr` of a `dict[int, str]` — e.g.\n * `\"{0: 'deworm', 1: 'not_deworm'}\"`. The value is parsed structurally (never\n * evaluated), and anything unparseable, non-`dict`, or not keyed by contiguous\n * integers from zero is rejected whole rather than half-applied: a partial name\n * map would silently mislabel predictions.\n *\n * @param metadata A model's custom metadata map.\n * @returns Class names in class-id order, or `null` when the model carries no\n * usable `names` entry.\n */\nexport function modelNames(\n metadata: Readonly<Record<string, string>> | undefined,\n): readonly string[] | null {\n return parseNames(metadata?.names);\n}\n\n/**\n * Parse a `repr`-encoded `dict[int, str]` class map.\n *\n * Split out of {@link modelNames} because the same encoding is reused by a\n * fused pipeline, which carries one class map per stage and therefore cannot\n * store both under the single `names` key Ultralytics uses.\n *\n * @param encoded The encoded map — e.g. `\"{0: 'deworm', 1: 'not_deworm'}\"`.\n * @returns Class names in class-id order, or `null` when the value is missing,\n * unparseable, not a `dict`, or not keyed by contiguous integers from zero.\n */\nexport function parseNames(encoded: string | undefined): readonly string[] | null {\n const raw = encoded?.trim();\n if (!raw || !raw.startsWith(\"{\") || !raw.endsWith(\"}\")) return null;\n\n const body = raw.slice(1, -1).trim();\n if (!body) return null;\n\n const names = new Map<number, string>();\n const entryPattern = /(-?\\d+)\\s*:\\s*(?:'((?:[^'\\\\]|\\\\.)*)'|\"((?:[^\"\\\\]|\\\\.)*)\")/g;\n let consumed = 0;\n for (const match of body.matchAll(entryPattern)) {\n const id = Number(match[1]);\n const text = match[2] ?? match[3];\n if (!Number.isInteger(id) || text === undefined) return null;\n names.set(id, unescapeQuoted(text));\n consumed += match[0].length;\n }\n if (names.size === 0) return null;\n\n const separators = body.length - consumed;\n if (separators > names.size * 3) return null;\n\n const ordered: string[] = [];\n for (let id = 0; id < names.size; id += 1) {\n const name = names.get(id);\n if (name === undefined) return null;\n ordered.push(name);\n }\n return ordered;\n}\n\n/**\n * Resolve the backslash escapes Python's `repr` emits inside a quoted string.\n *\n * @param text The quoted string's contents, escapes intact.\n * @returns The same text with `\\\\`, `\\'`, `\\\"`, `\\n`, `\\r` and `\\t` resolved.\n */\nfunction unescapeQuoted(text: string): string {\n return text.replace(/\\\\(.)/g, (_, char: string) => {\n if (char === \"n\") return \"\\n\";\n if (char === \"r\") return \"\\r\";\n if (char === \"t\") return \"\\t\";\n return char;\n });\n}\n"],"mappings":"AAwEA,SAAS,EAAW,GAA+B;CAC/C,IAAI,IAAS,GACT,IAAQ;CACZ,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAO,EAAO,MAAM,EAAO;EAGjC,IAFA,EAAO,OAAO,GACd,MAAW,IAAO,OAAQ,KAAK,GAC/B,EAAK,IAAO,MAAa,OAAO;EAEhC,IADA,KAAS,GACL,IAAQ,IAAI,OAAO;CAC3B;CACA,OAAO;AACX;AAUA,SAAS,EAAU,GAAgB,GAA2B;CAC1D,QAAQ,GAAR;EACI,KAAK,GACD,OAAO,EAAW,CAAM,MAAM;EAClC,KAAK,GAED,OADA,EAAO,OAAO,GACP,EAAO,OAAO,EAAO;EAChC,KAAK,GAAuB;GACxB,IAAM,IAAS,EAAW,CAAM;GAGhC,OAFI,MAAW,SACf,EAAO,OAAO,GACP,EAAO,OAAO,EAAO;EAChC;EACA,KAAK,GAED,OADA,EAAO,OAAO,GACP,EAAO,OAAO,EAAO;EAChC,SACI,OAAO;CACf;AACJ;AAYA,SAAS,EACL,GACA,IAAmB,SACkB;CACrC,IAAM,IAAS,EAAW,CAAM;CAChC,IAAI,MAAW,QAAQ,IAAS,GAAU,OAAO;CACjD,IAAM,IAAQ,EAAO,KACf,IAAM,IAAQ;CAGpB,OAFI,IAAM,EAAO,MAAY,QAC7B,EAAO,MAAM,GACN;EAAE;EAAO;CAAI;AACxB;AAUA,SAAS,EACL,GACA,GACA,GACgC;CAChC,IAAM,IAAiB;EAAE;EAAO;EAAK,KAAK;CAAM,GAC1C,IAAU,IAAI,YAAY,SAAS,EAAE,OAAO,GAAM,CAAC,GACrD,IAAqB,MACrB,IAAuB;CAE3B,OAAO,EAAO,MAAM,IAAK;EACrB,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM,OAAO;EACzB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IACI,MAAa,MACZ,MAAU,KAAmB,MAAU,IAC1C;GACE,IAAM,IAAQ,EAAoB,CAAM;GACxC,IAAI,MAAU,MAAM,OAAO;GAC3B,IAAM,IAAO,EAAQ,OAAO,EAAM,SAAS,EAAM,OAAO,EAAM,GAAG,CAAC;GAClE,AAAI,MAAU,IAAiB,IAAM,IAChC,IAAQ;GACb;EACJ;EACA,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG,OAAO;CAC7C;CAGA,OADI,MAAQ,QAAQ,MAAU,OAAa,OACpC,CAAC,GAAK,CAAK;AACtB;AAUA,SAAgB,EACZ,GACgC;CAChC,IAAM,IAAQ,aAAiB,aAAa,IAAQ,IAAI,WAAW,CAAK,GAClE,IAAiB;EAAE;EAAO,KAAK,EAAM;EAAQ,KAAK;CAAE,GACpD,IAAmC,CAAC;CAE1C,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM;EAClB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IAAI,MAAU,MAA8B,MAAa,GAAuB;GAC5E,IAAM,IAAQ,EAAoB,CAAM;GACxC,IAAI,MAAU,MAAM;GACpB,IAAM,IAAQ,EAAU,GAAO,EAAM,OAAO,EAAM,GAAG;GACrD,AAAI,MAAO,EAAS,EAAM,MAAM,EAAM;GACtC;EACJ;EACA,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG;CACtC;CAEA,OAAO;AACX;AAWA,SAAS,EAAmB,GAAmB,GAAe,GAA4B;CACtF,IAAM,IAAiB;EAAE;EAAO;EAAK,KAAK;CAAM;CAChD,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM,OAAO;EACzB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IAAI,MAAU,KAA0B,MAAa,GACjD,OAAO,EAAW,CAAM;EAE5B,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG,OAAO;CAC7C;CACA,OAAO;AACX;AAWA,SAAS,EAAiB,GAAmB,GAAe,GAA4B;CACpF,IAAM,IAAiB;EAAE;EAAO;EAAK,KAAK;CAAM;CAChD,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM,OAAO;EACzB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IAAI,MAAU,KAAqB,MAAa,GAAuB;GACnE,IAAM,IAAQ,EAAoB,CAAM;GAExC,OADI,MAAU,OAAa,OACpB,EAAmB,GAAO,EAAM,OAAO,EAAM,GAAG;EAC3D;EACA,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG,OAAO;CAC7C;CACA,OAAO;AACX;AAUA,SAAS,EACL,GACA,GACA,GACgC;CAChC,IAAM,IAAiB;EAAE;EAAO;EAAK,KAAK;CAAM,GAC5C,IAAsB,MACtB,IAA0B;CAC9B,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM,OAAO;EACzB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IAAI,MAAa,GAAuB;GACpC,IAAM,IAAQ,EAAoB,CAAM;GACxC,IAAI,MAAU,MAAM,OAAO;GAC3B,AAAI,MAAU,IACV,IAAO,IAAI,YAAY,SAAS,EAAE,OAAO,GAAM,CAAC,CAAC,CAAC,OAC9C,EAAM,SAAS,EAAM,OAAO,EAAM,GAAG,CACzC,IACO,MAAU,MACjB,IAAW,EAAiB,GAAO,EAAM,OAAO,EAAM,GAAG;GAE7D;EACJ;EACA,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG,OAAO;CAC7C;CAEA,OADI,MAAS,QAAQ,MAAa,OAAa,OACxC,CAAC,GAAM,CAAQ;AAC1B;AAgBA,SAAgB,EACZ,GACgC;CAChC,IAAM,IAAQ,aAAiB,aAAa,IAAQ,IAAI,WAAW,CAAK,GAClE,IAAiB;EAAE;EAAO,KAAK,EAAM;EAAQ,KAAK;CAAE,GACpD,IAAgC,CAAC;CAEvC,OAAO,EAAO,MAAM,EAAO,MAAK;EAC5B,IAAM,IAAM,EAAW,CAAM;EAC7B,IAAI,MAAQ,MAAM;EAClB,IAAM,IAAQ,MAAQ,GAChB,IAAW,IAAM;EACvB,IAAI,MAAU,KAAqB,MAAa,GAAuB;GACnE,IAAM,IAAQ,EAAoB,GAAQ,EAAM,MAAM;GACtD,IAAI,MAAU,MAAM;GACpB,IAAM,IAAgB;IAAE;IAAO,KAAK,EAAM;IAAK,KAAK,EAAM;GAAM;GAChE,OAAO,EAAM,MAAM,EAAM,MAAK;IAC1B,IAAM,IAAW,EAAW,CAAK;IACjC,IAAI,MAAa,MAAM;IACvB,IAAM,IAAa,MAAa,GAC1B,IAAY,IAAW;IAC7B,IAAI,MAAe,MAAqB,MAAc,GAAuB;KACzE,IAAM,IAAQ,EAAoB,CAAK;KACvC,IAAI,MAAU,MAAM;KACpB,IAAM,IAAO,EAAc,GAAO,EAAM,OAAO,EAAM,GAAG;KACxD,AAAI,MAAM,EAAM,EAAK,MAAM,EAAK;KAChC;IACJ;IACA,IAAI,CAAC,EAAU,GAAO,CAAS,GAAG;GACtC;GACA;EACJ;EACA,IAAI,CAAC,EAAU,GAAQ,CAAQ,GAAG;CACtC;CAEA,OAAO;AACX;AAeA,SAAgB,EACZ,GACwB;CACxB,OAAO,EAAW,GAAU,KAAK;AACrC;AAaA,SAAgB,EAAW,GAAuD;CAC9E,IAAM,IAAM,GAAS,KAAK;CAC1B,IAAI,CAAC,KAAO,CAAC,EAAI,WAAW,GAAG,KAAK,CAAC,EAAI,SAAS,GAAG,GAAG,OAAO;CAE/D,IAAM,IAAO,EAAI,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK;CACnC,IAAI,CAAC,GAAM,OAAO;CAElB,IAAM,oBAAQ,IAAI,IAAoB,GAChC,IAAe,8DACjB,IAAW;CACf,KAAK,IAAM,KAAS,EAAK,SAAS,CAAY,GAAG;EAC7C,IAAM,IAAK,OAAO,EAAM,EAAE,GACpB,IAAO,EAAM,MAAM,EAAM;EAC/B,IAAI,CAAC,OAAO,UAAU,CAAE,KAAK,MAAS,KAAA,GAAW,OAAO;EAExD,AADA,EAAM,IAAI,GAAI,EAAe,CAAI,CAAC,GAClC,KAAY,EAAM,EAAE,CAAC;CACzB;CAIA,IAHI,EAAM,SAAS,KAEA,EAAK,SAAS,IAChB,EAAM,OAAO,GAAG,OAAO;CAExC,IAAM,IAAoB,CAAC;CAC3B,KAAK,IAAI,IAAK,GAAG,IAAK,EAAM,MAAM,KAAM,GAAG;EACvC,IAAM,IAAO,EAAM,IAAI,CAAE;EACzB,IAAI,MAAS,KAAA,GAAW,OAAO;EAC/B,EAAQ,KAAK,CAAI;CACrB;CACA,OAAO;AACX;AAQA,SAAS,EAAe,GAAsB;CAC1C,OAAO,EAAK,QAAQ,WAAW,GAAG,MAC1B,MAAS,MAAY,OACrB,MAAS,MAAY,OACrB,MAAS,MAAY,MAClB,CACV;AACL"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=[`webgpu`,`wasm`],t=`wasm`;function n(t){return t===void 0||t.length===0?[...e]:[...t]}async function
|
|
1
|
+
var e=[`webgpu`,`wasm`],t=`wasm`;function n(e){return typeof e==`string`?e:e.name}function r(t){return t===void 0||t.length===0?[...e]:[...t]}async function i(e){let t=e.some(e=>n(e)===`webgpu`)?await a():!1;return e.filter(e=>{switch(n(e)){case`webgpu`:return t;case`webnn`:return typeof navigator<`u`&&`ml`in navigator;default:return!0}})}async function a(){let e=globalThis.navigator?.gpu;if(e===void 0)return!1;try{return await e.requestAdapter()!==null}catch{return!1}}exports.DEFAULT_PROVIDERS=e,exports.FALLBACK_PROVIDER=t,exports.detectProviders=i,exports.providerName=n,exports.resolveProviders=r;
|
|
2
2
|
//# sourceMappingURL=providers.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.cjs","names":[],"sources":["../../../src/vision/core/providers.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Execution-provider defaults for ONNX Runtime Web sessions.\n *\n * Unlike Node ORT, the browser ORT cannot enumerate \"available providers\" at\n * runtime — `webgpu` either works or ORT silently falls back to the next\n * provider in the list. We just expose a sensible default order.\n */\n\n/**\n * Default execution provider preference order for browser ORT.\n *\n * `webgpu` is tried first when available; ORT-Web falls back to `wasm`\n * automatically when WebGPU is not supported by the browser or device.\n */\nexport const DEFAULT_PROVIDERS: readonly string[] = [\"webgpu\", \"wasm\"];\n\n/**\n * The provider ORT-Web can always run, whatever the device.\n *\n * Used as the floor when capability detection rules everything else out. Passing\n * ORT a list it cannot satisfy is not a graceful failure — `InferenceSession.create`\n * rejects with \"no available backend found\" and the page gets no inference at\n * all, which is worse than the slow-but-working fallback the warning describes.\n */\nexport const FALLBACK_PROVIDER = \"wasm\";\n\n/**\n * Resolve the execution providers to pass to `InferenceSession.create`.\n *\n * @param requested Explicit provider list in preference order; `undefined` returns the default.\n */\nexport function resolveProviders(requested?: readonly
|
|
1
|
+
{"version":3,"file":"providers.cjs","names":[],"sources":["../../../src/vision/core/providers.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Execution-provider defaults for ONNX Runtime Web sessions.\n *\n * Unlike Node ORT, the browser ORT cannot enumerate \"available providers\" at\n * runtime — `webgpu` either works or ORT silently falls back to the next\n * provider in the list. We just expose a sensible default order.\n */\n\n/**\n * Default execution provider preference order for browser ORT.\n *\n * `webgpu` is tried first when available; ORT-Web falls back to `wasm`\n * automatically when WebGPU is not supported by the browser or device.\n */\nexport const DEFAULT_PROVIDERS: readonly string[] = [\"webgpu\", \"wasm\"];\n\n/**\n * The provider ORT-Web can always run, whatever the device.\n *\n * Used as the floor when capability detection rules everything else out. Passing\n * ORT a list it cannot satisfy is not a graceful failure — `InferenceSession.create`\n * rejects with \"no available backend found\" and the page gets no inference at\n * all, which is worse than the slow-but-working fallback the warning describes.\n */\nexport const FALLBACK_PROVIDER = \"wasm\";\n\n/**\n * One execution provider: its name, or ORT's config object for it.\n *\n * The object form carries provider options straight through to\n * `InferenceSession.create` — `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`,\n * `{ name: \"wasm\" }` — which a bare name cannot express.\n */\nexport type ProviderSpec = string | { readonly name: string; readonly [option: string]: unknown };\n\n/**\n * The provider name a spec refers to.\n *\n * @param spec A provider name or config object.\n */\nexport function providerName(spec: ProviderSpec): string {\n return typeof spec === \"string\" ? spec : spec.name;\n}\n\n/**\n * Resolve the execution providers to pass to `InferenceSession.create`.\n *\n * @param requested Explicit provider list in preference order, as names or\n * config objects; `undefined` or empty returns the default.\n */\nexport function resolveProviders<T extends ProviderSpec = string>(\n requested?: readonly T[],\n): (T | string)[] {\n if (requested === undefined || requested.length === 0) {\n return [...DEFAULT_PROVIDERS];\n }\n return [...requested];\n}\n\n/**\n * Narrow a provider list to the ones this browser can actually offer.\n *\n * ORT-Web exposes no equivalent of Node's `session.getProviders()`, so there is\n * no way to ask which provider a session ended up on. What the browser *does*\n * answer is whether the underlying API exists at all — no `navigator.gpu`, or no\n * adapter behind it, means `webgpu` was never going to run — and that covers the\n * case that actually bites: a page asking for WebGPU on a device without it,\n * silently getting WASM, and being several times slower than intended with no\n * error to point at.\n *\n * This is best-effort by construction. A provider that survives here can still\n * fail inside ORT for a reason the browser does not surface (a missing shader\n * feature, an exhausted device), so a surviving entry means \"not ruled out\",\n * not \"confirmed running\". Anything this function does not know how to test is\n * kept rather than dropped: guessing a provider away would be worse than\n * admitting ignorance about it.\n *\n * The WebGPU adapter is only requested when `webgpu` is in the list. Asking\n * unconditionally cost every WASM-only session a `requestAdapter()` round trip\n * and, on a machine without a GPU, a \"No available adapters\" console warning\n * per `create`.\n *\n * @param requested Providers in preference order, already resolved, as names\n * or config objects.\n * @returns The subset that is not ruled out, in the same order and form.\n */\nexport async function detectProviders<T extends ProviderSpec>(\n requested: readonly T[],\n): Promise<T[]> {\n const webgpu = requested.some((spec) => providerName(spec) === \"webgpu\")\n ? await hasWebGpuAdapter()\n : false;\n return requested.filter((spec) => {\n switch (providerName(spec)) {\n case \"webgpu\":\n return webgpu;\n case \"webnn\":\n return typeof navigator !== \"undefined\" && \"ml\" in navigator;\n default:\n return true;\n }\n });\n}\n\n/**\n * Whether this environment exposes a WebGPU adapter.\n *\n * `navigator.gpu` existing is not enough — a browser can ship the API and still\n * hand back no adapter (a blocklisted driver, a headless context, a machine with\n * no suitable GPU), which is exactly the configuration where a page asks for\n * WebGPU and quietly runs on WASM.\n */\nasync function hasWebGpuAdapter(): Promise<boolean> {\n const gpu = (\n globalThis.navigator as { gpu?: { requestAdapter(): Promise<unknown> } } | undefined\n )?.gpu;\n if (gpu === undefined) {\n return false;\n }\n try {\n return (await gpu.requestAdapter()) !== null;\n } catch {\n return false;\n }\n}\n"],"mappings":"AAeA,IAAa,EAAuC,CAAC,SAAU,MAAM,EAUxD,EAAoB,OAgBjC,SAAgB,EAAa,EAA4B,CACrD,OAAO,OAAO,GAAS,SAAW,EAAO,EAAK,IAClD,CAQA,SAAgB,EACZ,EACc,CAId,OAHI,IAAc,IAAA,IAAa,EAAU,SAAW,EACzC,CAAC,GAAG,CAAiB,EAEzB,CAAC,GAAG,CAAS,CACxB,CA6BA,eAAsB,EAClB,EACY,CACZ,IAAM,EAAS,EAAU,KAAM,GAAS,EAAa,CAAI,IAAM,QAAQ,EACjE,MAAM,EAAiB,EACvB,GACN,OAAO,EAAU,OAAQ,GAAS,CAC9B,OAAQ,EAAa,CAAI,EAAzB,CACI,IAAK,SACD,OAAO,EACX,IAAK,QACD,OAAO,OAAO,UAAc,KAAe,OAAQ,UACvD,QACI,MAAO,EACf,CACJ,CAAC,CACL,CAUA,eAAe,GAAqC,CAChD,IAAM,EACF,WAAW,WACZ,IACH,GAAI,IAAQ,IAAA,GACR,MAAO,GAEX,GAAI,CACA,OAAQ,MAAM,EAAI,eAAe,IAAO,IAC5C,MAAQ,CACJ,MAAO,EACX,CACJ"}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
//#region src/vision/core/providers.ts
|
|
2
2
|
var e = ["webgpu", "wasm"], t = "wasm";
|
|
3
|
-
function n(
|
|
3
|
+
function n(e) {
|
|
4
|
+
return typeof e == "string" ? e : e.name;
|
|
5
|
+
}
|
|
6
|
+
function r(t) {
|
|
4
7
|
return t === void 0 || t.length === 0 ? [...e] : [...t];
|
|
5
8
|
}
|
|
6
|
-
async function
|
|
7
|
-
let t = await
|
|
9
|
+
async function i(e) {
|
|
10
|
+
let t = e.some((e) => n(e) === "webgpu") ? await a() : !1;
|
|
8
11
|
return e.filter((e) => {
|
|
9
|
-
switch (e) {
|
|
12
|
+
switch (n(e)) {
|
|
10
13
|
case "webgpu": return t;
|
|
11
14
|
case "webnn": return typeof navigator < "u" && "ml" in navigator;
|
|
12
15
|
default: return !0;
|
|
13
16
|
}
|
|
14
17
|
});
|
|
15
18
|
}
|
|
16
|
-
async function
|
|
19
|
+
async function a() {
|
|
17
20
|
let e = globalThis.navigator?.gpu;
|
|
18
21
|
if (e === void 0) return !1;
|
|
19
22
|
try {
|
|
@@ -23,6 +26,6 @@ async function i() {
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
//#endregion
|
|
26
|
-
export { e as DEFAULT_PROVIDERS, t as FALLBACK_PROVIDER,
|
|
29
|
+
export { e as DEFAULT_PROVIDERS, t as FALLBACK_PROVIDER, i as detectProviders, n as providerName, r as resolveProviders };
|
|
27
30
|
|
|
28
31
|
//# sourceMappingURL=providers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.js","names":[],"sources":["../../../src/vision/core/providers.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Execution-provider defaults for ONNX Runtime Web sessions.\n *\n * Unlike Node ORT, the browser ORT cannot enumerate \"available providers\" at\n * runtime — `webgpu` either works or ORT silently falls back to the next\n * provider in the list. We just expose a sensible default order.\n */\n\n/**\n * Default execution provider preference order for browser ORT.\n *\n * `webgpu` is tried first when available; ORT-Web falls back to `wasm`\n * automatically when WebGPU is not supported by the browser or device.\n */\nexport const DEFAULT_PROVIDERS: readonly string[] = [\"webgpu\", \"wasm\"];\n\n/**\n * The provider ORT-Web can always run, whatever the device.\n *\n * Used as the floor when capability detection rules everything else out. Passing\n * ORT a list it cannot satisfy is not a graceful failure — `InferenceSession.create`\n * rejects with \"no available backend found\" and the page gets no inference at\n * all, which is worse than the slow-but-working fallback the warning describes.\n */\nexport const FALLBACK_PROVIDER = \"wasm\";\n\n/**\n * Resolve the execution providers to pass to `InferenceSession.create`.\n *\n * @param requested Explicit provider list in preference order; `undefined` returns the default.\n */\nexport function resolveProviders(requested?: readonly
|
|
1
|
+
{"version":3,"file":"providers.js","names":[],"sources":["../../../src/vision/core/providers.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Execution-provider defaults for ONNX Runtime Web sessions.\n *\n * Unlike Node ORT, the browser ORT cannot enumerate \"available providers\" at\n * runtime — `webgpu` either works or ORT silently falls back to the next\n * provider in the list. We just expose a sensible default order.\n */\n\n/**\n * Default execution provider preference order for browser ORT.\n *\n * `webgpu` is tried first when available; ORT-Web falls back to `wasm`\n * automatically when WebGPU is not supported by the browser or device.\n */\nexport const DEFAULT_PROVIDERS: readonly string[] = [\"webgpu\", \"wasm\"];\n\n/**\n * The provider ORT-Web can always run, whatever the device.\n *\n * Used as the floor when capability detection rules everything else out. Passing\n * ORT a list it cannot satisfy is not a graceful failure — `InferenceSession.create`\n * rejects with \"no available backend found\" and the page gets no inference at\n * all, which is worse than the slow-but-working fallback the warning describes.\n */\nexport const FALLBACK_PROVIDER = \"wasm\";\n\n/**\n * One execution provider: its name, or ORT's config object for it.\n *\n * The object form carries provider options straight through to\n * `InferenceSession.create` — `{ name: \"webgpu\", preferredLayout: \"NHWC\" }`,\n * `{ name: \"wasm\" }` — which a bare name cannot express.\n */\nexport type ProviderSpec = string | { readonly name: string; readonly [option: string]: unknown };\n\n/**\n * The provider name a spec refers to.\n *\n * @param spec A provider name or config object.\n */\nexport function providerName(spec: ProviderSpec): string {\n return typeof spec === \"string\" ? spec : spec.name;\n}\n\n/**\n * Resolve the execution providers to pass to `InferenceSession.create`.\n *\n * @param requested Explicit provider list in preference order, as names or\n * config objects; `undefined` or empty returns the default.\n */\nexport function resolveProviders<T extends ProviderSpec = string>(\n requested?: readonly T[],\n): (T | string)[] {\n if (requested === undefined || requested.length === 0) {\n return [...DEFAULT_PROVIDERS];\n }\n return [...requested];\n}\n\n/**\n * Narrow a provider list to the ones this browser can actually offer.\n *\n * ORT-Web exposes no equivalent of Node's `session.getProviders()`, so there is\n * no way to ask which provider a session ended up on. What the browser *does*\n * answer is whether the underlying API exists at all — no `navigator.gpu`, or no\n * adapter behind it, means `webgpu` was never going to run — and that covers the\n * case that actually bites: a page asking for WebGPU on a device without it,\n * silently getting WASM, and being several times slower than intended with no\n * error to point at.\n *\n * This is best-effort by construction. A provider that survives here can still\n * fail inside ORT for a reason the browser does not surface (a missing shader\n * feature, an exhausted device), so a surviving entry means \"not ruled out\",\n * not \"confirmed running\". Anything this function does not know how to test is\n * kept rather than dropped: guessing a provider away would be worse than\n * admitting ignorance about it.\n *\n * The WebGPU adapter is only requested when `webgpu` is in the list. Asking\n * unconditionally cost every WASM-only session a `requestAdapter()` round trip\n * and, on a machine without a GPU, a \"No available adapters\" console warning\n * per `create`.\n *\n * @param requested Providers in preference order, already resolved, as names\n * or config objects.\n * @returns The subset that is not ruled out, in the same order and form.\n */\nexport async function detectProviders<T extends ProviderSpec>(\n requested: readonly T[],\n): Promise<T[]> {\n const webgpu = requested.some((spec) => providerName(spec) === \"webgpu\")\n ? await hasWebGpuAdapter()\n : false;\n return requested.filter((spec) => {\n switch (providerName(spec)) {\n case \"webgpu\":\n return webgpu;\n case \"webnn\":\n return typeof navigator !== \"undefined\" && \"ml\" in navigator;\n default:\n return true;\n }\n });\n}\n\n/**\n * Whether this environment exposes a WebGPU adapter.\n *\n * `navigator.gpu` existing is not enough — a browser can ship the API and still\n * hand back no adapter (a blocklisted driver, a headless context, a machine with\n * no suitable GPU), which is exactly the configuration where a page asks for\n * WebGPU and quietly runs on WASM.\n */\nasync function hasWebGpuAdapter(): Promise<boolean> {\n const gpu = (\n globalThis.navigator as { gpu?: { requestAdapter(): Promise<unknown> } } | undefined\n )?.gpu;\n if (gpu === undefined) {\n return false;\n }\n try {\n return (await gpu.requestAdapter()) !== null;\n } catch {\n return false;\n }\n}\n"],"mappings":";AAeA,IAAa,IAAuC,CAAC,UAAU,MAAM,GAUxD,IAAoB;AAgBjC,SAAgB,EAAa,GAA4B;CACrD,OAAO,OAAO,KAAS,WAAW,IAAO,EAAK;AAClD;AAQA,SAAgB,EACZ,GACc;CAId,OAHI,MAAc,KAAA,KAAa,EAAU,WAAW,IACzC,CAAC,GAAG,CAAiB,IAEzB,CAAC,GAAG,CAAS;AACxB;AA6BA,eAAsB,EAClB,GACY;CACZ,IAAM,IAAS,EAAU,MAAM,MAAS,EAAa,CAAI,MAAM,QAAQ,IACjE,MAAM,EAAiB,IACvB;CACN,OAAO,EAAU,QAAQ,MAAS;EAC9B,QAAQ,EAAa,CAAI,GAAzB;GACI,KAAK,UACD,OAAO;GACX,KAAK,SACD,OAAO,OAAO,YAAc,OAAe,QAAQ;GACvD,SACI,OAAO;EACf;CACJ,CAAC;AACL;AAUA,eAAe,IAAqC;CAChD,IAAM,IACF,WAAW,WACZ;CACH,IAAI,MAAQ,KAAA,GACR,OAAO;CAEX,IAAI;EACA,OAAQ,MAAM,EAAI,eAAe,MAAO;CAC5C,QAAQ;EACJ,OAAO;CACX;AACJ"}
|