Text Generation
Transformers.js
ONNX
llama
webgpu
q4f16
gptq
tool-calling
experimental
conversational
Instructions to use webbrain-one/webbrain-compass-tiny-v2.1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers.js
How to use webbrain-one/webbrain-compass-tiny-v2.1 with Transformers.js:
// npm i @huggingface/transformers import { pipeline } from '@huggingface/transformers'; // Allocate pipeline const pipe = await pipeline('text-generation', 'webbrain-one/webbrain-compass-tiny-v2.1');
Release Compass Tiny v2.1: tested v24 q4f16 WebGPU, validation and caveats
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +3 -0
- ARTIFACTS.json +261 -0
- ATTRIBUTIONS.md +17 -0
- PROVENANCE.json +270 -0
- README.md +153 -0
- chat_template.jinja +176 -0
- config.json +43 -0
- generation_config.json +11 -0
- integration/minicpm5-tool-parser.mjs +101 -0
- integration/parser.test.mjs +40 -0
- onnx/model_q4f16.onnx +3 -0
- onnx/model_q4f16.onnx_data +3 -0
- onnx/model_q4f16.onnx_data_1 +3 -0
- runtime/inference-worker.js +1539 -0
- runtime/tool-call-parser.js +512 -0
- runtime/vendor/LICENSE.onnxruntime.txt +21 -0
- runtime/vendor/LICENSE.transformers.txt +202 -0
- runtime/vendor/README.md +162 -0
- runtime/vendor/ThirdPartyNotices.onnxruntime.txt +0 -0
- runtime/vendor/onnxruntime-common/backend-impl.js +142 -0
- runtime/vendor/onnxruntime-common/backend.js +4 -0
- runtime/vendor/onnxruntime-common/env-impl.js +25 -0
- runtime/vendor/onnxruntime-common/env.js +8 -0
- runtime/vendor/onnxruntime-common/index.js +27 -0
- runtime/vendor/onnxruntime-common/inference-session-impl.js +208 -0
- runtime/vendor/onnxruntime-common/inference-session.js +6 -0
- runtime/vendor/onnxruntime-common/onnx-model.js +4 -0
- runtime/vendor/onnxruntime-common/onnx-value.js +4 -0
- runtime/vendor/onnxruntime-common/tensor-conversion-impl.js +195 -0
- runtime/vendor/onnxruntime-common/tensor-conversion.js +4 -0
- runtime/vendor/onnxruntime-common/tensor-factory-impl.js +265 -0
- runtime/vendor/onnxruntime-common/tensor-factory.js +4 -0
- runtime/vendor/onnxruntime-common/tensor-impl-type-mapping.js +58 -0
- runtime/vendor/onnxruntime-common/tensor-impl.js +366 -0
- runtime/vendor/onnxruntime-common/tensor-utils-impl.js +62 -0
- runtime/vendor/onnxruntime-common/tensor-utils.js +4 -0
- runtime/vendor/onnxruntime-common/tensor.js +6 -0
- runtime/vendor/onnxruntime-common/trace.js +69 -0
- runtime/vendor/onnxruntime-common/type-helper.js +4 -0
- runtime/vendor/onnxruntime-common/version.js +6 -0
- runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs +112 -0
- runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm +3 -0
- runtime/vendor/ort.webgpu.mjs +0 -0
- runtime/vendor/transformers.web.js +0 -0
- tokenizer.json +3 -0
- tokenizer_config.json +18 -0
- validation/cold-cache-results.json +29 -0
- validation/context-results.json +31 -0
- validation/numerical-results.json +319 -0
- validation/parser-results.json +92 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
onnx/model_q4f16.onnx_data filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
onnx/model_q4f16.onnx_data_1 filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
ARTIFACTS.json
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "exact-v24-webgpu-q4f16-plus-explicit-integration-helper",
|
| 3 |
+
"manifestExcludesItself": true,
|
| 4 |
+
"files": [
|
| 5 |
+
{
|
| 6 |
+
"path": "ATTRIBUTIONS.md",
|
| 7 |
+
"bytes": 964,
|
| 8 |
+
"sha256": "3d83117ca74892774eedf2c3288ba864de05e4f0fe242bb4d09885e8634100a6"
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"path": "chat_template.jinja",
|
| 12 |
+
"bytes": 8986,
|
| 13 |
+
"sha256": "23ac861c8370f36819f4f6034c4439ff631e3c381855749451a02be85d19b2d6"
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"path": "config.json",
|
| 17 |
+
"bytes": 951,
|
| 18 |
+
"sha256": "504e5e43d11c25189f59896801302a8c40b3caf14cedc9dd9dc050c6430dcc01"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"path": "generation_config.json",
|
| 22 |
+
"bytes": 186,
|
| 23 |
+
"sha256": "6f66aa5aaf68145027c3f3c384abfd837530fe4d1efb582e0aa919eecd4c9a8e"
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"path": "integration/minicpm5-tool-parser.mjs",
|
| 27 |
+
"bytes": 5307,
|
| 28 |
+
"sha256": "0f1bf7265771ec5cf73147c299c52490086579bb2d2c9885cbddda7e067322e3"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"path": "integration/parser.test.mjs",
|
| 32 |
+
"bytes": 2376,
|
| 33 |
+
"sha256": "ca3a366878b648e4daeba1674aead2c9b2a11f21c6308ed3a416c986632521ba"
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"path": "onnx/model_q4f16.onnx",
|
| 37 |
+
"bytes": 362892,
|
| 38 |
+
"sha256": "ab10bc051ca80ad6dffe5045acac030d0d6b75c52d90db363d044f1f214fccfa"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"path": "onnx/model_q4f16.onnx_data",
|
| 42 |
+
"bytes": 1596739584,
|
| 43 |
+
"sha256": "2abad6aebb250a04619df22e8b2cab9998ee92ba083ec5426c97ae1beb8476f7"
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"path": "onnx/model_q4f16.onnx_data_1",
|
| 47 |
+
"bytes": 272252928,
|
| 48 |
+
"sha256": "715887fa2ce24f2f1d5f5f8adaebc0caac4bad02e7d4d90e081f85decefec244"
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"path": "PROVENANCE.json",
|
| 52 |
+
"bytes": 11378,
|
| 53 |
+
"sha256": "f6cd6d8e5f4947c2b09308731dd58352c7c4a4897dedfeed1e81baf2837e97d9"
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"path": "README.md",
|
| 57 |
+
"bytes": 8044,
|
| 58 |
+
"sha256": "e601af5ecf40c128ba3510f1c1a89edc1d63013901490b30e569311ffae3235c"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"path": "runtime/inference-worker.js",
|
| 62 |
+
"bytes": 58199,
|
| 63 |
+
"sha256": "6e8863a72f022fa8d12207d4029f8f33f339f3c2c066497618065cf642da85dd"
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"path": "runtime/tool-call-parser.js",
|
| 67 |
+
"bytes": 18197,
|
| 68 |
+
"sha256": "7a33bbcd31cc3910a169e735541c4d5189f85480237577f262de3154ce91f12d"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"path": "runtime/vendor/LICENSE.onnxruntime.txt",
|
| 72 |
+
"bytes": 1073,
|
| 73 |
+
"sha256": "2f07c72751aed99790b8a4869cf2311df85a860b22ded05fa22803587a48922c"
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"path": "runtime/vendor/LICENSE.transformers.txt",
|
| 77 |
+
"bytes": 11358,
|
| 78 |
+
"sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"path": "runtime/vendor/onnxruntime-common/backend-impl.js",
|
| 82 |
+
"bytes": 5339,
|
| 83 |
+
"sha256": "97dd81b055a06f61120f09468fe59f046a9262b7b87bf5d05bceb085bf4f5558"
|
| 84 |
+
},
|
| 85 |
+
{
|
| 86 |
+
"path": "runtime/vendor/onnxruntime-common/backend.js",
|
| 87 |
+
"bytes": 184,
|
| 88 |
+
"sha256": "017ce2ec9dc2021ebc1ef2c4f04e1bc74276c65921b0297e7ed8cc16e640495b"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"path": "runtime/vendor/onnxruntime-common/env-impl.js",
|
| 92 |
+
"bytes": 848,
|
| 93 |
+
"sha256": "0da4c562a49fe147e19320a64cbb456184eb0e6242b1fe69c65c8368c55f3d97"
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"path": "runtime/vendor/onnxruntime-common/env.js",
|
| 97 |
+
"bytes": 262,
|
| 98 |
+
"sha256": "b2bbd3d3b00a95765713c57cd0f5ef73718ae5b8322e07cb47a43e2accb21f15"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"path": "runtime/vendor/onnxruntime-common/index.js",
|
| 102 |
+
"bytes": 1036,
|
| 103 |
+
"sha256": "ad23f6d6ce2c99c449031f24a5181f259516c64a9a67428c98a8539b857729bd"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"path": "runtime/vendor/onnxruntime-common/inference-session-impl.js",
|
| 107 |
+
"bytes": 8703,
|
| 108 |
+
"sha256": "0446814a392c147b5c38ba242d9911ee54002b5d01a8e19fb4895fb8f8a0cdd3"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"path": "runtime/vendor/onnxruntime-common/inference-session.js",
|
| 112 |
+
"bytes": 348,
|
| 113 |
+
"sha256": "3ad4271a88edb3d242dc1e0e7bbf66510f9a56eff874c433b3b37f900ac007b1"
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"path": "runtime/vendor/onnxruntime-common/onnx-model.js",
|
| 117 |
+
"bytes": 145,
|
| 118 |
+
"sha256": "9e9dc8678be0ea04575a542894508db355a4f9f2155ac7f4c17a697c5f843382"
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"path": "runtime/vendor/onnxruntime-common/onnx-value.js",
|
| 122 |
+
"bytes": 145,
|
| 123 |
+
"sha256": "33dc232498753fc9026dfa44c99440cb1a6d29f3e53e1ad2fb8b696705158f06"
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-conversion-impl.js",
|
| 127 |
+
"bytes": 7852,
|
| 128 |
+
"sha256": "df6fa3cd1813c2d3e588cc07973cfe5ea2ab8647c957168200caa58e51440161"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-conversion.js",
|
| 132 |
+
"bytes": 152,
|
| 133 |
+
"sha256": "8c43ec1d061ab71032a1b28f45d85ef95f8d7bd2d4cd71d059e96d83e3a8f422"
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-factory-impl.js",
|
| 137 |
+
"bytes": 11002,
|
| 138 |
+
"sha256": "cf5606fe23461e01bff59c2d72ac47d74e652548718f1e5fab07a22b441379b4"
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-factory.js",
|
| 142 |
+
"bytes": 149,
|
| 143 |
+
"sha256": "68b9f4f4573f25012ce8a4f73c9a2cee3a28db91de8bbb0a20ddb08bcba33c4b"
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-impl-type-mapping.js",
|
| 147 |
+
"bytes": 2706,
|
| 148 |
+
"sha256": "20bd5ddb858954cf071bace6c7a6628c8e311433798ec172f4c778bebd81d407"
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-impl.js",
|
| 152 |
+
"bytes": 16091,
|
| 153 |
+
"sha256": "6a749be63055f9d21069566b1515412484a3a03448ca20427c8f8d29328a2843"
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-utils-impl.js",
|
| 157 |
+
"bytes": 1920,
|
| 158 |
+
"sha256": "87d3e07c153616138c2f57846545eea9c47957c714d50c0264696bdc293e6732"
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-utils.js",
|
| 162 |
+
"bytes": 147,
|
| 163 |
+
"sha256": "7acfdb2f8403ae84b7ae62d55d6eeb01519108be8874337b317b911ed60190cd"
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"path": "runtime/vendor/onnxruntime-common/tensor.js",
|
| 167 |
+
"bytes": 286,
|
| 168 |
+
"sha256": "721d24a538de5333057bfc423bc00c3453a1c483f4495c857d0a6f9b8f2d330e"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"path": "runtime/vendor/onnxruntime-common/trace.js",
|
| 172 |
+
"bytes": 1891,
|
| 173 |
+
"sha256": "9b87e6309a1c502b03558aa94b0a65c8ea1e8eb59cb46090f54f6eacd191b841"
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"path": "runtime/vendor/onnxruntime-common/type-helper.js",
|
| 177 |
+
"bytes": 146,
|
| 178 |
+
"sha256": "3e2588c6a5ee7b9755e199eef10c6aa2e777d0366ea47d27953657a5638deeae"
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"path": "runtime/vendor/onnxruntime-common/version.js",
|
| 182 |
+
"bytes": 263,
|
| 183 |
+
"sha256": "00a18ffb867b29a3855fe00e965797dba270849134f1e0ab2929fb2761c0fe44"
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"path": "runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs",
|
| 187 |
+
"bytes": 47507,
|
| 188 |
+
"sha256": "7236653b8565da4046e459cd0e274123419a1d9f1f8f18fd36c28058346ca655"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"path": "runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm",
|
| 192 |
+
"bytes": 24254953,
|
| 193 |
+
"sha256": "7e83cd6cee77e478bc96a7e91b198144fb5e4126287daf1f9b54bb195ebcd55a"
|
| 194 |
+
},
|
| 195 |
+
{
|
| 196 |
+
"path": "runtime/vendor/ort.webgpu.mjs",
|
| 197 |
+
"bytes": 679694,
|
| 198 |
+
"sha256": "177cf67f3e6c25e951a76a981a857e6af53b1571016685cc2480e1e6e47b1d46"
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"path": "runtime/vendor/README.md",
|
| 202 |
+
"bytes": 8373,
|
| 203 |
+
"sha256": "a3b6d952b825a7382f16f89c1431e57090e6c3c2d1267ce1548069c802c103c7"
|
| 204 |
+
},
|
| 205 |
+
{
|
| 206 |
+
"path": "runtime/vendor/ThirdPartyNotices.onnxruntime.txt",
|
| 207 |
+
"bytes": 325054,
|
| 208 |
+
"sha256": "0e07b95f3a8d6230037707c5c4a2b554d12c4cb67369669ac255635528ffcee2"
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"path": "runtime/vendor/transformers.web.js",
|
| 212 |
+
"bytes": 1099925,
|
| 213 |
+
"sha256": "83e3edd00c98fef962da9bdc22fe4b63b3858743a76c1b7e46bee8e483033644"
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"path": "tokenizer.json",
|
| 217 |
+
"bytes": 10548223,
|
| 218 |
+
"sha256": "c7dc553ba83607a7d3cde4782e4055fcd15cb228f8f1cdc3fc149b1094580592"
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"path": "tokenizer_config.json",
|
| 222 |
+
"bytes": 9706,
|
| 223 |
+
"sha256": "f8a13de1b9989de61731cf9ce5805a9c3da2aad822ded0cd5375cc3d1206e24c"
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"path": "validation/cold-cache-results.json",
|
| 227 |
+
"bytes": 988,
|
| 228 |
+
"sha256": "ea1382b4cf397eed54510c2ac362f8c53c519d1a0bacd58a5266a44ceffb8972"
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"path": "validation/context-results.json",
|
| 232 |
+
"bytes": 693,
|
| 233 |
+
"sha256": "c59e23f5038d5a6dd3d4e67f7ba90036d24af117a5c834221e30fc533a44e565"
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
"path": "validation/numerical-results.json",
|
| 237 |
+
"bytes": 8506,
|
| 238 |
+
"sha256": "d8d09941d44038efe040ad748d034d217f7e43227cd28ff5e47edfe061c80d4f"
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"path": "validation/parser-results.json",
|
| 242 |
+
"bytes": 2257,
|
| 243 |
+
"sha256": "b50a394c4ddd5cfacf9208e8b8cbd39e3a048dbab5211bebc781ffb612f06bb1"
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"path": "validation/parser-unit-tests.json",
|
| 247 |
+
"bytes": 804,
|
| 248 |
+
"sha256": "cdeef39b880727cf70b0578dd90dec8941edd007fa3eae0225cbbf6810bd4626"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"path": "validation/routing-results.json",
|
| 252 |
+
"bytes": 1316,
|
| 253 |
+
"sha256": "924be9a083ccd11206a528f6e63c64f743078e9a451a69fe968ba6f98cfcc2a4"
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"path": "validation/smoke-results.json",
|
| 257 |
+
"bytes": 2009,
|
| 258 |
+
"sha256": "9f478ce6bd8c9f6ddb145e4468ae31f5290a8aaedfa4673a06483f1b0e7b66c9"
|
| 259 |
+
}
|
| 260 |
+
]
|
| 261 |
+
}
|
ATTRIBUTIONS.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Source attributions and project restrictions
|
| 2 |
+
|
| 3 |
+
Base: OpenBMB MiniCPM5-2B, revision 3497c460c89e00520c3cfa2e73f49ab7647f1177,
|
| 4 |
+
Apache-2.0. https://huggingface.co/openbmb/MiniCPM5-2B
|
| 5 |
+
Modified by WebBrain through LoRA training and full-model merging.
|
| 6 |
+
Original authors do not endorse this derived release.
|
| 7 |
+
|
| 8 |
+
Training dataset: https://huggingface.co/datasets/webbrain-one/webbrain-compass-v2-dataset
|
| 9 |
+
Preserve the source attributions, manifests and restrictions in that private repository.
|
| 10 |
+
WebLINX: McGill-NLP contributors, CC BY-NC-SA 4.0.
|
| 11 |
+
https://huggingface.co/datasets/McGill-NLP/weblinx
|
| 12 |
+
https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.en
|
| 13 |
+
|
| 14 |
+
Project policy restricts this derived model to noncommercial research. Preserve
|
| 15 |
+
all source terms, attribution and applicable share-alike obligations. Private
|
| 16 |
+
hosting does not grant commercial rights. This is an experimental release with
|
| 17 |
+
a disclosed failed behavioral gate, not a claim of general safety or success.
|
PROVENANCE.json
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"releaseName": "WebBrain Compass Tiny v2.1",
|
| 3 |
+
"repository": "webbrain-one/webbrain-compass-tiny-v2.1",
|
| 4 |
+
"candidate": "v24",
|
| 5 |
+
"status": "private-experimental-release-authorized",
|
| 6 |
+
"authorization": "Owner requested release of v24 as webbrain-compass-tiny-v2.1 after receiving the numerical pass, parser caveat and three discouraged-action results. Private visibility retained.",
|
| 7 |
+
"numericalValidationPassed": true,
|
| 8 |
+
"numericalToleranceChanged": false,
|
| 9 |
+
"behavioralGatePassed": false,
|
| 10 |
+
"productionReleaseApproved": false,
|
| 11 |
+
"endToEndBrowserTaskSuccessMeasured": false,
|
| 12 |
+
"sourcePackageProofSha256": "dc91e19a96db79d51d77c15c1e03f755249021ae0fbf3403e4606ed877a664a1",
|
| 13 |
+
"sourceNumericalCompletionSha256": "d8d09941d44038efe040ad748d034d217f7e43227cd28ff5e47edfe061c80d4f",
|
| 14 |
+
"sourceBehavioralAuditSha256": "43e5a2d408995796994245d396a1b61522fe1185574b29fb07e47ff8de7a7365",
|
| 15 |
+
"historicalEvidenceUnchanged": true,
|
| 16 |
+
"change": "Same trained model; 211 MatMulNBits accuracy_level attributes 4 -> 2; no weight, tokenizer or runtime changes.",
|
| 17 |
+
"sourceBf16Repo": "webbrain-one/webbrain-compass-tiny-v2",
|
| 18 |
+
"sourceBf16Revision": "54bcab6731939137d0489ac01463c9404dff9da8",
|
| 19 |
+
"priorRelease": {
|
| 20 |
+
"repo": "webbrain-one/webbrain-compass-tiny-v2-onnx",
|
| 21 |
+
"revision": "efddf2666bced055e9b04e745197b4e7d56734e0",
|
| 22 |
+
"unchanged": true
|
| 23 |
+
},
|
| 24 |
+
"testedTransportAlias": "webbrain-one/webbrain-compass-tiny-v2-onnx",
|
| 25 |
+
"newRepoIsTransportRenameOnly": true,
|
| 26 |
+
"browser": "150.0.7871.187",
|
| 27 |
+
"hardware": "NVIDIA RTX 5090",
|
| 28 |
+
"runtime": {
|
| 29 |
+
"transformers.js": "4.2.0",
|
| 30 |
+
"onnxruntime-web": "1.27.0"
|
| 31 |
+
},
|
| 32 |
+
"testedBytes": [
|
| 33 |
+
{
|
| 34 |
+
"sourcePath": "bundle/chat_template.jinja",
|
| 35 |
+
"path": "chat_template.jinja",
|
| 36 |
+
"bytes": 8986,
|
| 37 |
+
"sha256": "23ac861c8370f36819f4f6034c4439ff631e3c381855749451a02be85d19b2d6"
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"sourcePath": "bundle/config.json",
|
| 41 |
+
"path": "config.json",
|
| 42 |
+
"bytes": 951,
|
| 43 |
+
"sha256": "504e5e43d11c25189f59896801302a8c40b3caf14cedc9dd9dc050c6430dcc01"
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"sourcePath": "bundle/generation_config.json",
|
| 47 |
+
"path": "generation_config.json",
|
| 48 |
+
"bytes": 186,
|
| 49 |
+
"sha256": "6f66aa5aaf68145027c3f3c384abfd837530fe4d1efb582e0aa919eecd4c9a8e"
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"sourcePath": "bundle/onnx/model_q4f16.onnx",
|
| 53 |
+
"path": "onnx/model_q4f16.onnx",
|
| 54 |
+
"bytes": 362892,
|
| 55 |
+
"sha256": "ab10bc051ca80ad6dffe5045acac030d0d6b75c52d90db363d044f1f214fccfa"
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"sourcePath": "bundle/onnx/model_q4f16.onnx_data",
|
| 59 |
+
"path": "onnx/model_q4f16.onnx_data",
|
| 60 |
+
"bytes": 1596739584,
|
| 61 |
+
"sha256": "2abad6aebb250a04619df22e8b2cab9998ee92ba083ec5426c97ae1beb8476f7"
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"sourcePath": "bundle/onnx/model_q4f16.onnx_data_1",
|
| 65 |
+
"path": "onnx/model_q4f16.onnx_data_1",
|
| 66 |
+
"bytes": 272252928,
|
| 67 |
+
"sha256": "715887fa2ce24f2f1d5f5f8adaebc0caac4bad02e7d4d90e081f85decefec244"
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"sourcePath": "bundle/tokenizer.json",
|
| 71 |
+
"path": "tokenizer.json",
|
| 72 |
+
"bytes": 10548223,
|
| 73 |
+
"sha256": "c7dc553ba83607a7d3cde4782e4055fcd15cb228f8f1cdc3fc149b1094580592"
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"sourcePath": "bundle/tokenizer_config.json",
|
| 77 |
+
"path": "tokenizer_config.json",
|
| 78 |
+
"bytes": 9706,
|
| 79 |
+
"sha256": "f8a13de1b9989de61731cf9ce5805a9c3da2aad822ded0cd5375cc3d1206e24c"
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"sourcePath": "runtime/inference-worker.js",
|
| 83 |
+
"path": "runtime/inference-worker.js",
|
| 84 |
+
"bytes": 58199,
|
| 85 |
+
"sha256": "6e8863a72f022fa8d12207d4029f8f33f339f3c2c066497618065cf642da85dd"
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"sourcePath": "runtime/tool-call-parser.js",
|
| 89 |
+
"path": "runtime/tool-call-parser.js",
|
| 90 |
+
"bytes": 18197,
|
| 91 |
+
"sha256": "7a33bbcd31cc3910a169e735541c4d5189f85480237577f262de3154ce91f12d"
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"sourcePath": "runtime/vendor/LICENSE.onnxruntime.txt",
|
| 95 |
+
"path": "runtime/vendor/LICENSE.onnxruntime.txt",
|
| 96 |
+
"bytes": 1073,
|
| 97 |
+
"sha256": "2f07c72751aed99790b8a4869cf2311df85a860b22ded05fa22803587a48922c"
|
| 98 |
+
},
|
| 99 |
+
{
|
| 100 |
+
"sourcePath": "runtime/vendor/LICENSE.transformers.txt",
|
| 101 |
+
"path": "runtime/vendor/LICENSE.transformers.txt",
|
| 102 |
+
"bytes": 11358,
|
| 103 |
+
"sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/backend-impl.js",
|
| 107 |
+
"path": "runtime/vendor/onnxruntime-common/backend-impl.js",
|
| 108 |
+
"bytes": 5339,
|
| 109 |
+
"sha256": "97dd81b055a06f61120f09468fe59f046a9262b7b87bf5d05bceb085bf4f5558"
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/backend.js",
|
| 113 |
+
"path": "runtime/vendor/onnxruntime-common/backend.js",
|
| 114 |
+
"bytes": 184,
|
| 115 |
+
"sha256": "017ce2ec9dc2021ebc1ef2c4f04e1bc74276c65921b0297e7ed8cc16e640495b"
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/env-impl.js",
|
| 119 |
+
"path": "runtime/vendor/onnxruntime-common/env-impl.js",
|
| 120 |
+
"bytes": 848,
|
| 121 |
+
"sha256": "0da4c562a49fe147e19320a64cbb456184eb0e6242b1fe69c65c8368c55f3d97"
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/env.js",
|
| 125 |
+
"path": "runtime/vendor/onnxruntime-common/env.js",
|
| 126 |
+
"bytes": 262,
|
| 127 |
+
"sha256": "b2bbd3d3b00a95765713c57cd0f5ef73718ae5b8322e07cb47a43e2accb21f15"
|
| 128 |
+
},
|
| 129 |
+
{
|
| 130 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/index.js",
|
| 131 |
+
"path": "runtime/vendor/onnxruntime-common/index.js",
|
| 132 |
+
"bytes": 1036,
|
| 133 |
+
"sha256": "ad23f6d6ce2c99c449031f24a5181f259516c64a9a67428c98a8539b857729bd"
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/inference-session-impl.js",
|
| 137 |
+
"path": "runtime/vendor/onnxruntime-common/inference-session-impl.js",
|
| 138 |
+
"bytes": 8703,
|
| 139 |
+
"sha256": "0446814a392c147b5c38ba242d9911ee54002b5d01a8e19fb4895fb8f8a0cdd3"
|
| 140 |
+
},
|
| 141 |
+
{
|
| 142 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/inference-session.js",
|
| 143 |
+
"path": "runtime/vendor/onnxruntime-common/inference-session.js",
|
| 144 |
+
"bytes": 348,
|
| 145 |
+
"sha256": "3ad4271a88edb3d242dc1e0e7bbf66510f9a56eff874c433b3b37f900ac007b1"
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/onnx-model.js",
|
| 149 |
+
"path": "runtime/vendor/onnxruntime-common/onnx-model.js",
|
| 150 |
+
"bytes": 145,
|
| 151 |
+
"sha256": "9e9dc8678be0ea04575a542894508db355a4f9f2155ac7f4c17a697c5f843382"
|
| 152 |
+
},
|
| 153 |
+
{
|
| 154 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/onnx-value.js",
|
| 155 |
+
"path": "runtime/vendor/onnxruntime-common/onnx-value.js",
|
| 156 |
+
"bytes": 145,
|
| 157 |
+
"sha256": "33dc232498753fc9026dfa44c99440cb1a6d29f3e53e1ad2fb8b696705158f06"
|
| 158 |
+
},
|
| 159 |
+
{
|
| 160 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-conversion-impl.js",
|
| 161 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-conversion-impl.js",
|
| 162 |
+
"bytes": 7852,
|
| 163 |
+
"sha256": "df6fa3cd1813c2d3e588cc07973cfe5ea2ab8647c957168200caa58e51440161"
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-conversion.js",
|
| 167 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-conversion.js",
|
| 168 |
+
"bytes": 152,
|
| 169 |
+
"sha256": "8c43ec1d061ab71032a1b28f45d85ef95f8d7bd2d4cd71d059e96d83e3a8f422"
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-factory-impl.js",
|
| 173 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-factory-impl.js",
|
| 174 |
+
"bytes": 11002,
|
| 175 |
+
"sha256": "cf5606fe23461e01bff59c2d72ac47d74e652548718f1e5fab07a22b441379b4"
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-factory.js",
|
| 179 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-factory.js",
|
| 180 |
+
"bytes": 149,
|
| 181 |
+
"sha256": "68b9f4f4573f25012ce8a4f73c9a2cee3a28db91de8bbb0a20ddb08bcba33c4b"
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-impl-type-mapping.js",
|
| 185 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-impl-type-mapping.js",
|
| 186 |
+
"bytes": 2706,
|
| 187 |
+
"sha256": "20bd5ddb858954cf071bace6c7a6628c8e311433798ec172f4c778bebd81d407"
|
| 188 |
+
},
|
| 189 |
+
{
|
| 190 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-impl.js",
|
| 191 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-impl.js",
|
| 192 |
+
"bytes": 16091,
|
| 193 |
+
"sha256": "6a749be63055f9d21069566b1515412484a3a03448ca20427c8f8d29328a2843"
|
| 194 |
+
},
|
| 195 |
+
{
|
| 196 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-utils-impl.js",
|
| 197 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-utils-impl.js",
|
| 198 |
+
"bytes": 1920,
|
| 199 |
+
"sha256": "87d3e07c153616138c2f57846545eea9c47957c714d50c0264696bdc293e6732"
|
| 200 |
+
},
|
| 201 |
+
{
|
| 202 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor-utils.js",
|
| 203 |
+
"path": "runtime/vendor/onnxruntime-common/tensor-utils.js",
|
| 204 |
+
"bytes": 147,
|
| 205 |
+
"sha256": "7acfdb2f8403ae84b7ae62d55d6eeb01519108be8874337b317b911ed60190cd"
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/tensor.js",
|
| 209 |
+
"path": "runtime/vendor/onnxruntime-common/tensor.js",
|
| 210 |
+
"bytes": 286,
|
| 211 |
+
"sha256": "721d24a538de5333057bfc423bc00c3453a1c483f4495c857d0a6f9b8f2d330e"
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/trace.js",
|
| 215 |
+
"path": "runtime/vendor/onnxruntime-common/trace.js",
|
| 216 |
+
"bytes": 1891,
|
| 217 |
+
"sha256": "9b87e6309a1c502b03558aa94b0a65c8ea1e8eb59cb46090f54f6eacd191b841"
|
| 218 |
+
},
|
| 219 |
+
{
|
| 220 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/type-helper.js",
|
| 221 |
+
"path": "runtime/vendor/onnxruntime-common/type-helper.js",
|
| 222 |
+
"bytes": 146,
|
| 223 |
+
"sha256": "3e2588c6a5ee7b9755e199eef10c6aa2e777d0366ea47d27953657a5638deeae"
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"sourcePath": "runtime/vendor/onnxruntime-common/version.js",
|
| 227 |
+
"path": "runtime/vendor/onnxruntime-common/version.js",
|
| 228 |
+
"bytes": 263,
|
| 229 |
+
"sha256": "00a18ffb867b29a3855fe00e965797dba270849134f1e0ab2929fb2761c0fe44"
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"sourcePath": "runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs",
|
| 233 |
+
"path": "runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs",
|
| 234 |
+
"bytes": 47507,
|
| 235 |
+
"sha256": "7236653b8565da4046e459cd0e274123419a1d9f1f8f18fd36c28058346ca655"
|
| 236 |
+
},
|
| 237 |
+
{
|
| 238 |
+
"sourcePath": "runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm",
|
| 239 |
+
"path": "runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm",
|
| 240 |
+
"bytes": 24254953,
|
| 241 |
+
"sha256": "7e83cd6cee77e478bc96a7e91b198144fb5e4126287daf1f9b54bb195ebcd55a"
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"sourcePath": "runtime/vendor/ort.webgpu.mjs",
|
| 245 |
+
"path": "runtime/vendor/ort.webgpu.mjs",
|
| 246 |
+
"bytes": 679694,
|
| 247 |
+
"sha256": "177cf67f3e6c25e951a76a981a857e6af53b1571016685cc2480e1e6e47b1d46"
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"sourcePath": "runtime/vendor/README.md",
|
| 251 |
+
"path": "runtime/vendor/README.md",
|
| 252 |
+
"bytes": 8373,
|
| 253 |
+
"sha256": "a3b6d952b825a7382f16f89c1431e57090e6c3c2d1267ce1548069c802c103c7"
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"sourcePath": "runtime/vendor/ThirdPartyNotices.onnxruntime.txt",
|
| 257 |
+
"path": "runtime/vendor/ThirdPartyNotices.onnxruntime.txt",
|
| 258 |
+
"bytes": 325054,
|
| 259 |
+
"sha256": "0e07b95f3a8d6230037707c5c4a2b554d12c4cb67369669ac255635528ffcee2"
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"sourcePath": "runtime/vendor/transformers.web.js",
|
| 263 |
+
"path": "runtime/vendor/transformers.web.js",
|
| 264 |
+
"bytes": 1099925,
|
| 265 |
+
"sha256": "83e3edd00c98fef962da9bdc22fe4b63b3858743a76c1b7e46bee8e483033644"
|
| 266 |
+
}
|
| 267 |
+
],
|
| 268 |
+
"optionalParserIncludedSeparately": true,
|
| 269 |
+
"bundledParserReplaced": false
|
| 270 |
+
}
|
README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: webbrain-noncommercial-research-restrictions
|
| 4 |
+
license_link: https://huggingface.co/webbrain-one/webbrain-compass-tiny-v2.1/blob/main/ATTRIBUTIONS.md
|
| 5 |
+
library_name: transformers.js
|
| 6 |
+
base_model: webbrain-one/webbrain-compass-tiny-v2
|
| 7 |
+
pipeline_tag: text-generation
|
| 8 |
+
tags:
|
| 9 |
+
- onnx
|
| 10 |
+
- webgpu
|
| 11 |
+
- q4f16
|
| 12 |
+
- gptq
|
| 13 |
+
- tool-calling
|
| 14 |
+
- experimental
|
| 15 |
+
---
|
| 16 |
+
# WebBrain Compass Tiny v2.1
|
| 17 |
+
|
| 18 |
+
**Private experimental q4f16/WebGPU release of the tested v24 candidate.**
|
| 19 |
+
Based on WebBrain Compass Tiny v2, a fine-tune of **OpenBMB MiniCPM5-2B (~2.6B parameters)**.
|
| 20 |
+
v2.1 is an **export/runtime revision**, not a new training run. The merged BF16 source remains
|
| 21 |
+
`webbrain-one/webbrain-compass-tiny-v2` at `54bcab6731939137d0489ac01463c9404dff9da8`.
|
| 22 |
+
The previous v23 release is separate and unchanged.
|
| 23 |
+
|
| 24 |
+
## What improved
|
| 25 |
+
|
| 26 |
+
Only the ONNX graph's 211 `MatMulNBits` `accuracy_level` attributes changed from 4 to 2,
|
| 27 |
+
disabling the dynamic INT8-activation path used in the pinned WebGPU runtime. Quantized
|
| 28 |
+
weight shards, tokenizer, config and vendored runtime remain byte-identical to v23.
|
| 29 |
+
|
| 30 |
+
| Check | v23 | v2.1 / v24 |
|
| 31 |
+
|---|---:|---:|
|
| 32 |
+
| Quantized PyTorch vs WebGPU numerical checks | 2/12 pass | **12/12 pass** |
|
| 33 |
+
| Worst relative RMS logit difference; unchanged limit 2% | 6.5274% | **1.8334%** |
|
| 34 |
+
| Minimum cosine; unchanged limit 0.999 | 0.998065500 | **0.999833960** |
|
| 35 |
+
|
| 36 |
+
Generation smoke (8 cases), bounded **16,384-total-token** context/cache checks, and a
|
| 37 |
+
cold-browser restart with model downloads disabled passed. All three cold-cache native
|
| 38 |
+
tool-call outputs were unchanged. Numerical tests cover three prompts, prefill plus
|
| 39 |
+
three cached steps each, with identical token prefixes. They establish runtime parity
|
| 40 |
+
in those probes—not BF16 equivalence, universal numerical accuracy, or a percentage
|
| 41 |
+
loss in task accuracy. INT4 quality loss remains a separate issue; a Turkish smoke
|
| 42 |
+
response remained awkward despite passing structural checks.
|
| 43 |
+
|
| 44 |
+
## Fixed next-response routing results
|
| 45 |
+
|
| 46 |
+
| Metric | BF16 reference | v2.1 / v24 WebGPU |
|
| 47 |
+
|---|---:|---:|
|
| 48 |
+
| First-turn structured calls | 94/100 | **98/100** |
|
| 49 |
+
| Strict exact action | 16/89 | **15/89** |
|
| 50 |
+
| Loose tool-family match | 41/89 | **43/89** |
|
| 51 |
+
|
| 52 |
+
This is **not end-to-end browser-agent task success or an Online-Mind2Web result**.
|
| 53 |
+
One run: 100 first-turn cases, 89 scored scenarios and 11 predetermined skips;
|
| 54 |
+
194 raw responses including 5 smoke requests were retained locally. The 193 pinned
|
| 55 |
+
input files match the BF16 reference, but precision, runtime and JS/Torch random
|
| 56 |
+
generators differ. No output repair, model helper, fallback or result-based retry.
|
| 57 |
+
|
| 58 |
+
**The full predeclared behavioral gate failed:** 3 explicitly discouraged actions
|
| 59 |
+
versus a limit of 1. These were retrying an access-blocked URL, continuing a listing
|
| 60 |
+
before reporting available results, and inventing a pagination URL. Other declared
|
| 61 |
+
gates passed, with zero transport errors, zero native-decoder parser errors and zero
|
| 62 |
+
length-limited responses. The owner authorized this separate release with these
|
| 63 |
+
findings disclosed; it is not certified for unattended consequential actions.
|
| 64 |
+
|
| 65 |
+
## Exact package
|
| 66 |
+
|
| 67 |
+
- GPTQ asymmetric INT4 weights, group size 32; FP16 scales/activations/KV cache.
|
| 68 |
+
- Default graph: `onnx/model_q4f16.onnx`. **Both** external data files are required:
|
| 69 |
+
`model_q4f16.onnx_data` and `model_q4f16.onnx_data_1` (1,868,992,512 bytes combined).
|
| 70 |
+
- The inherited BF16 dtype and 131072 architecture field in `config.json` do not
|
| 71 |
+
describe this quantized graph or establish a tested browser context limit.
|
| 72 |
+
- Exact tested runtime under `runtime/`: Transformers.js **4.2.0**, ONNX Runtime Web
|
| 73 |
+
**1.27.0**, WebBrain worker/parser and dependency licences. Tested with Chrome
|
| 74 |
+
**150.0.7871.187**, NVIDIA **RTX 5090**. Other devices/runtimes are not verified here.
|
| 75 |
+
- Generation-only, last-token logits; thinking disabled. No cloud or visual model.
|
| 76 |
+
- Tests used a local model transport alias; this repository name is the release
|
| 77 |
+
identifier. All 39 tested model/runtime files are mapped and hashed in provenance.
|
| 78 |
+
- `validation/` contains results and compact audit summaries. Complete original
|
| 79 |
+
local audit hashes are recorded; private training/calibration data, browser profiles,
|
| 80 |
+
credentials and raw benchmark requests are not included.
|
| 81 |
+
|
| 82 |
+
## Integration
|
| 83 |
+
|
| 84 |
+
1. Download the **pinned commit returned with the release**, using an HF account with
|
| 85 |
+
private-repository access:
|
| 86 |
+
|
| 87 |
+
```sh
|
| 88 |
+
hf download webbrain-one/webbrain-compass-tiny-v2.1 --revision <PINNED_COMMIT> --local-dir ./compass-tiny-v2.1
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
Keep `onnx/`, tokenizer/config files and both external shards together. Never embed
|
| 92 |
+
a personal/write token in an extension, webpage, source file or log. Use a trusted
|
| 93 |
+
authenticated asset proxy or a private local mirror pinned to that same commit.
|
| 94 |
+
Anonymous HF downloads cannot access this private release.
|
| 95 |
+
|
| 96 |
+
2. In WebBrain, choose the custom model ID `webbrain-one/webbrain-compass-tiny-v2.1`,
|
| 97 |
+
**device `webgpu`, dtype `q4f16`**, default filename stem `model`. Use the supplied
|
| 98 |
+
runtime assets. The unchanged worker has no revision option: pin the asset proxy,
|
| 99 |
+
or explicitly pass `revision` at pipeline initialization in your integration.
|
| 100 |
+
The new model ID has a separate cache key; do not alias it onto v23's cached graph.
|
| 101 |
+
|
| 102 |
+
Equivalent library initialization, with executable runtime assets served locally:
|
| 103 |
+
|
| 104 |
+
```js
|
| 105 |
+
import { env, pipeline } from './runtime/vendor/transformers.web.js';
|
| 106 |
+
import { parseMiniCpmToolCalls } from './integration/minicpm5-tool-parser.mjs';
|
| 107 |
+
|
| 108 |
+
env.backends.onnx.wasm.numThreads = 1;
|
| 109 |
+
env.backends.onnx.wasm.wasmPaths = {
|
| 110 |
+
mjs: new URL('./runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs', import.meta.url).href,
|
| 111 |
+
wasm: new URL('./runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm', import.meta.url).href,
|
| 112 |
+
};
|
| 113 |
+
// Configure your trusted authenticated asset proxy before accessing this private repo.
|
| 114 |
+
const generator = await pipeline('text-generation',
|
| 115 |
+
'webbrain-one/webbrain-compass-tiny-v2.1', {
|
| 116 |
+
revision: '<PINNED_COMMIT>', device: 'webgpu', dtype: 'q4f16',
|
| 117 |
+
session_options: { extra: {
|
| 118 |
+
'ep.webgpuexecutionprovider.storageBufferCacheMode': 'simple',
|
| 119 |
+
} },
|
| 120 |
+
});
|
| 121 |
+
try {
|
| 122 |
+
const result = await generator(messages, {
|
| 123 |
+
tools, do_sample: false, max_new_tokens: 256,
|
| 124 |
+
tokenizer_encode_kwargs: { enable_thinking: false },
|
| 125 |
+
});
|
| 126 |
+
const generated = result[0].generated_text;
|
| 127 |
+
const text = Array.isArray(generated) ? generated.at(-1).content : generated;
|
| 128 |
+
const calls = parseMiniCpmToolCalls(text, tools);
|
| 129 |
+
// Retain raw text. Validate argument schemas and user authorization before dispatch.
|
| 130 |
+
// An empty calls list is not automatically successful task completion.
|
| 131 |
+
} finally {
|
| 132 |
+
await generator.dispose();
|
| 133 |
+
}
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
The native custom-model worker defaults to greedy generation and caps output at
|
| 137 |
+
256 tokens. The routing benchmark used its documented test hook (4096-token budget,
|
| 138 |
+
temperature 0.15/0.3, seed 3407); do not claim those scores for the default UI settings.
|
| 139 |
+
Budget input plus output within the tested 16K limit and start with short tasks.
|
| 140 |
+
|
| 141 |
+
3. **Parser integration is explicit, not silently changed.** The exact bundled parser
|
| 142 |
+
under `runtime/` matches 162/194 recorded native-decoder responses. It can leave
|
| 143 |
+
Python-style `False` and `['green', 'amber']` as strings. The optional, separately
|
| 144 |
+
audited `integration/minicpm5-tool-parser.mjs` matches **194/194** recorded responses
|
| 145 |
+
and passed its allowlist checks; it is not automatically wired into the worker.
|
| 146 |
+
Pass the full tool schemas so string-valued JSON bodies remain strings. The helper
|
| 147 |
+
does not execute literals, validate every schema constraint, or grant action approval.
|
| 148 |
+
Preserve downstream validation, confirmations and raw-output/error logging.
|
| 149 |
+
|
| 150 |
+
CPU-only helper checks: `node --test integration/parser.test.mjs`.
|
| 151 |
+
|
| 152 |
+
This release remains subject to `ATTRIBUTIONS.md`, including the project's
|
| 153 |
+
noncommercial-research restrictions. Private hosting does not expand usage rights.
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{- bos_token }}{%- if tools %}
|
| 2 |
+
{%- set tool_definitions %}
|
| 3 |
+
{{- "# Tools\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
|
| 4 |
+
{%- for tool in tools %}
|
| 5 |
+
{{- "\n" }}
|
| 6 |
+
{{- tool | tojson(ensure_ascii=False) }}
|
| 7 |
+
{%- endfor %}
|
| 8 |
+
{{- '\n</tools>\n\nTool usage guidelines:\n- You may call zero or more functions. If no function calls are needed, just answer normally and do not include any <function ... </function>.\n- When calling a function, return an XML object within <function ... </function> using:\n<function name="function-name"><param name="param-name">param-value</param></function>\n- param-value may be multi-line. If it contains <, & or newline characters, wrap it in a CDATA block: <param name="param-name"><![CDATA[...multi-line value...]]></param>' }}
|
| 9 |
+
{%- endset %}
|
| 10 |
+
|
| 11 |
+
{{- '<|im_start|>system\n' }}
|
| 12 |
+
{%- if messages[0].role == 'system' %}
|
| 13 |
+
{%- if '<tool_def_sep>' in messages[0].content %}
|
| 14 |
+
{{- messages[0].content.replace('<tool_def_sep>', tool_definitions) }}
|
| 15 |
+
{%- else %}
|
| 16 |
+
{{- messages[0].content + '\n\n' + tool_definitions }}
|
| 17 |
+
{%- endif %}
|
| 18 |
+
{%- else %}
|
| 19 |
+
{{- tool_definitions.lstrip() }}
|
| 20 |
+
{%- endif %}
|
| 21 |
+
{{- '<|im_end|>\n' }}
|
| 22 |
+
{%- else %}
|
| 23 |
+
{%- if messages[0].role == 'system' %}
|
| 24 |
+
{{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
|
| 25 |
+
{%- endif %}
|
| 26 |
+
{%- endif %}
|
| 27 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 28 |
+
{%- for message in messages[::-1] %}
|
| 29 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 30 |
+
{%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
|
| 31 |
+
{%- set ns.multi_step_tool = false %}
|
| 32 |
+
{%- set ns.last_query_index = index %}
|
| 33 |
+
{%- endif %}
|
| 34 |
+
{%- endfor %}
|
| 35 |
+
{%- for message in messages %}
|
| 36 |
+
{%- if message.content is string %}
|
| 37 |
+
{%- set content = message.content %}
|
| 38 |
+
{%- else %}
|
| 39 |
+
{%- set content = '' %}
|
| 40 |
+
{%- endif %}
|
| 41 |
+
{%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
|
| 42 |
+
{{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
|
| 43 |
+
{%- elif message.role == "assistant" %}
|
| 44 |
+
{%- set reasoning_content = '' %}
|
| 45 |
+
{%- if message.reasoning_content is string %}
|
| 46 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 47 |
+
{%- else %}
|
| 48 |
+
{%- if '</think>' in content %}
|
| 49 |
+
{%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 50 |
+
{%- set content = content.split('</think>')[-1].lstrip('\n') %}
|
| 51 |
+
{%- endif %}
|
| 52 |
+
{%- endif %}
|
| 53 |
+
|
| 54 |
+
{%- if message.tool_calls %}
|
| 55 |
+
{%- set content_parts = content.split('<tool_sep>') %}
|
| 56 |
+
{%- set processed_content = content_parts[0] %}
|
| 57 |
+
{%- set tool_calls_count = message.tool_calls|length %}
|
| 58 |
+
{%- set tool_sep_count = content_parts|length - 1 %}
|
| 59 |
+
|
| 60 |
+
{%- for i in range(1, content_parts|length) %}
|
| 61 |
+
{%- set tool_index = i - 1 %}
|
| 62 |
+
{%- if tool_index < tool_calls_count %}
|
| 63 |
+
{%- set tool_call = message.tool_calls[tool_index] %}
|
| 64 |
+
{%- if tool_call.function %}
|
| 65 |
+
{%- set tool_call = tool_call.function %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{%- set single_tool_xml %}
|
| 68 |
+
{{- '<function name="' ~ tool_call.name ~ '">' }}
|
| 69 |
+
{%- if tool_call.arguments %}
|
| 70 |
+
{%- set args_dict = tool_call.arguments %}
|
| 71 |
+
{%- for param_name, param_value in args_dict.items() %}
|
| 72 |
+
{{- '<param name="' ~ param_name ~ '">' }}
|
| 73 |
+
{%- if param_value is string and ('<' in param_value or '&' in param_value or '\n' in param_value) %}
|
| 74 |
+
{{- '<![CDATA[' + param_value + ']]>' }}
|
| 75 |
+
{%- else %}
|
| 76 |
+
{{- param_value }}
|
| 77 |
+
{%- endif %}
|
| 78 |
+
{{- '</param>' }}
|
| 79 |
+
{%- endfor %}
|
| 80 |
+
{%- endif %}
|
| 81 |
+
{{- '</function>' }}
|
| 82 |
+
{%- endset %}
|
| 83 |
+
{%- set processed_content = processed_content + single_tool_xml + content_parts[i] %}
|
| 84 |
+
{%- else %}
|
| 85 |
+
{%- set processed_content = processed_content + content_parts[i] %}
|
| 86 |
+
{%- endif %}
|
| 87 |
+
{%- endfor %}
|
| 88 |
+
|
| 89 |
+
{%- if tool_calls_count > tool_sep_count %}
|
| 90 |
+
{%- for remaining_index in range(tool_sep_count, tool_calls_count) %}
|
| 91 |
+
{%- set tool_call = message.tool_calls[remaining_index] %}
|
| 92 |
+
{%- if tool_call.function %}
|
| 93 |
+
{%- set tool_call = tool_call.function %}
|
| 94 |
+
{%- endif %}
|
| 95 |
+
{%- set remaining_tool_xml %}
|
| 96 |
+
{{- '<function name="' ~ tool_call.name ~ '">' }}
|
| 97 |
+
{%- if tool_call.arguments %}
|
| 98 |
+
{%- set args_dict = tool_call.arguments %}
|
| 99 |
+
{%- for param_name, param_value in args_dict.items() %}
|
| 100 |
+
{{- '<param name="' ~ param_name ~ '">' }}
|
| 101 |
+
{%- if param_value is string and ('<' in param_value or '&' in param_value or '\n' in param_value) %}
|
| 102 |
+
{{- '<![CDATA[' + param_value + ']]>' }}
|
| 103 |
+
{%- else %}
|
| 104 |
+
{{- param_value }}
|
| 105 |
+
{%- endif %}
|
| 106 |
+
{{- '</param>' }}
|
| 107 |
+
{%- endfor %}
|
| 108 |
+
{%- endif %}
|
| 109 |
+
{{- '</function>' }}
|
| 110 |
+
{%- endset %}
|
| 111 |
+
{%- set processed_content = processed_content + remaining_tool_xml %}
|
| 112 |
+
{%- endfor %}
|
| 113 |
+
{%- endif %}
|
| 114 |
+
|
| 115 |
+
{%- set content = processed_content %}
|
| 116 |
+
{%- endif %}
|
| 117 |
+
|
| 118 |
+
{%- if reasoning_content %}
|
| 119 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
|
| 120 |
+
{%- elif '<think>' not in content and '</think>' not in content %}
|
| 121 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n\n</think>\n\n' + content.lstrip('\n') }}
|
| 122 |
+
{%- else %}
|
| 123 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 124 |
+
{%- endif %}
|
| 125 |
+
|
| 126 |
+
{%- if message.tool_calls and not has_tool_sep %}
|
| 127 |
+
{%- for tool_call in message.tool_calls %}
|
| 128 |
+
{%- if (loop.first and content) or (not loop.first) %}
|
| 129 |
+
{{- '\n' }}
|
| 130 |
+
{%- endif %}
|
| 131 |
+
{%- if tool_call.function %}
|
| 132 |
+
{%- set tool_call = tool_call.function %}
|
| 133 |
+
{%- endif %}
|
| 134 |
+
{{- '<function name="' ~ tool_call.name ~ '">' }}
|
| 135 |
+
{%- if tool_call.arguments %}
|
| 136 |
+
{%- set args_dict = tool_call.arguments %}
|
| 137 |
+
{%- for param_name, param_value in args_dict.items() %}
|
| 138 |
+
{{- '<param name="' ~ param_name ~ '">' }}
|
| 139 |
+
{%- if param_value is string and ('<' in param_value or '&' in param_value or '\n' in param_value) %}
|
| 140 |
+
{{- '<![CDATA[' + param_value + ']]>' }}
|
| 141 |
+
{%- else %}
|
| 142 |
+
{{- param_value }}
|
| 143 |
+
{%- endif %}
|
| 144 |
+
{{- '</param>' }}
|
| 145 |
+
{%- endfor %}
|
| 146 |
+
{%- endif %}
|
| 147 |
+
{{- '</function>' }}
|
| 148 |
+
{%- endfor %}
|
| 149 |
+
{%- endif %}
|
| 150 |
+
{{- '<|im_end|>\n' }}
|
| 151 |
+
{%- elif message.role == "tool" %}
|
| 152 |
+
{%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
|
| 153 |
+
{{- '<|im_start|>user' }}
|
| 154 |
+
{%- endif %}
|
| 155 |
+
{{- '\n<tool_response>\n' }}
|
| 156 |
+
{%- if message.content is string %}
|
| 157 |
+
{{- content }}
|
| 158 |
+
{%- else %}
|
| 159 |
+
{{- message.content | tojson(ensure_ascii=False) }}
|
| 160 |
+
{%- endif %}
|
| 161 |
+
{{- '\n</tool_response>' }}
|
| 162 |
+
{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
|
| 163 |
+
{{- '<|im_end|>\n' }}
|
| 164 |
+
{%- endif %}
|
| 165 |
+
{%- endif %}
|
| 166 |
+
{%- endfor %}
|
| 167 |
+
{%- if add_generation_prompt %}
|
| 168 |
+
{{- '<|im_start|>assistant\n' }}
|
| 169 |
+
{%- if enable_thinking is defined %}
|
| 170 |
+
{%- if enable_thinking is false %}
|
| 171 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 172 |
+
{%- elif enable_thinking is true %}
|
| 173 |
+
{{- '<think>\n' }}
|
| 174 |
+
{%- endif %}
|
| 175 |
+
{%- endif %}
|
| 176 |
+
{%- endif %}
|
config.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"LlamaForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"bos_token_id": 0,
|
| 8 |
+
"dtype": "bfloat16",
|
| 9 |
+
"eos_token_id": [
|
| 10 |
+
1,
|
| 11 |
+
130073
|
| 12 |
+
],
|
| 13 |
+
"head_dim": 128,
|
| 14 |
+
"hidden_act": "silu",
|
| 15 |
+
"hidden_size": 2048,
|
| 16 |
+
"initializer_range": 0.02,
|
| 17 |
+
"intermediate_size": 6144,
|
| 18 |
+
"max_position_embeddings": 131072,
|
| 19 |
+
"mlp_bias": false,
|
| 20 |
+
"model_type": "llama",
|
| 21 |
+
"num_attention_heads": 16,
|
| 22 |
+
"num_hidden_layers": 42,
|
| 23 |
+
"num_key_value_heads": 2,
|
| 24 |
+
"pad_token_id": 1,
|
| 25 |
+
"pretraining_tp": 1,
|
| 26 |
+
"rms_norm_eps": 1e-06,
|
| 27 |
+
"rope_parameters": {
|
| 28 |
+
"rope_theta": 5000000,
|
| 29 |
+
"rope_type": "default"
|
| 30 |
+
},
|
| 31 |
+
"tie_word_embeddings": false,
|
| 32 |
+
"transformers_version": "5.16.1",
|
| 33 |
+
"use_cache": true,
|
| 34 |
+
"vocab_size": 130560,
|
| 35 |
+
"transformers.js_config": {
|
| 36 |
+
"kv_cache_dtype": {
|
| 37 |
+
"q4f16": "float16"
|
| 38 |
+
},
|
| 39 |
+
"use_external_data_format": {
|
| 40 |
+
"model_q4f16.onnx": 2
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
}
|
generation_config.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 0,
|
| 4 |
+
"eos_token_id": [
|
| 5 |
+
1,
|
| 6 |
+
130073
|
| 7 |
+
],
|
| 8 |
+
"pad_token_id": 1,
|
| 9 |
+
"transformers_version": "5.16.1",
|
| 10 |
+
"use_cache": true
|
| 11 |
+
}
|
integration/minicpm5-tool-parser.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// MiniCPM5 native XML uses Python literals for typed parameters. No eval/Function.
|
| 2 |
+
export function parseMiniCpmParamValue(input, schema = {}) {
|
| 3 |
+
const raw = String(input ?? '');
|
| 4 |
+
const cdata = /^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/.exec(raw);
|
| 5 |
+
let decoded=cdata ? cdata[1] : raw;
|
| 6 |
+
if(!cdata) {
|
| 7 |
+
if(raw.includes('<')) throw Error('Malformed XML parameter: use CDATA for literal markup');
|
| 8 |
+
decoded=raw.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);/gi,(_,entity)=>{
|
| 9 |
+
if(entity.startsWith('#')) { const n=entity[1].toLowerCase()==='x'?parseInt(entity.slice(2),16):parseInt(entity.slice(1),10);return String.fromCodePoint(n); }
|
| 10 |
+
return {amp:'&',lt:'<',gt:'>',quot:'"',apos:"'"}[entity];
|
| 11 |
+
});
|
| 12 |
+
if(/&(?!(?:#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);)/i.test(raw)) throw Error('Unescaped XML ampersand');
|
| 13 |
+
}
|
| 14 |
+
if(schema.type==='string') return decoded;
|
| 15 |
+
const text = decoded.trim();
|
| 16 |
+
if (!text) return '';
|
| 17 |
+
let i = 0;
|
| 18 |
+
const ws = () => { while (i < text.length && /\s/u.test(text[i])) i++; };
|
| 19 |
+
const take = char => { ws(); if (text[i++] !== char) throw Error('Invalid literal'); };
|
| 20 |
+
function value(depth = 0) {
|
| 21 |
+
if (depth > 32) throw Error('Literal nesting limit');
|
| 22 |
+
ws();
|
| 23 |
+
const c = text[i];
|
| 24 |
+
if (c === "'" || c === '"') {
|
| 25 |
+
const quote = text[i++]; let result = '';
|
| 26 |
+
while (i < text.length) {
|
| 27 |
+
const ch = text[i++];
|
| 28 |
+
if (ch === quote) return result;
|
| 29 |
+
if (ch !== '\\') { result += ch; continue; }
|
| 30 |
+
const e = text[i++];
|
| 31 |
+
const simple = { '\\':'\\', "'":"'", '"':'"', n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', '/':'/' };
|
| 32 |
+
if (Object.hasOwn(simple,e)) { result += simple[e]; continue; }
|
| 33 |
+
const width = e === 'u' ? 4 : e === 'x' ? 2 : 0;
|
| 34 |
+
const hex = text.slice(i,i+width);
|
| 35 |
+
if (!width || !new RegExp(`^[a-fA-F0-9]{${width}}$`).test(hex)) throw Error('Invalid escape');
|
| 36 |
+
result += String.fromCharCode(parseInt(hex,16)); i += width;
|
| 37 |
+
}
|
| 38 |
+
throw Error('Unterminated string');
|
| 39 |
+
}
|
| 40 |
+
if (c === '[' || c === '{') {
|
| 41 |
+
i++; const array = c === '['; const end = array ? ']' : '}';
|
| 42 |
+
const result = array ? [] : Object.create(null);
|
| 43 |
+
ws(); if (text[i] === end) { i++; return array ? result : {...result}; }
|
| 44 |
+
while (i < text.length) {
|
| 45 |
+
if (array) result.push(value(depth+1));
|
| 46 |
+
else {
|
| 47 |
+
ws(); if (!['"',"'"].includes(text[i])) throw Error('Expected string key');
|
| 48 |
+
const key = value(depth+1);
|
| 49 |
+
if (Object.hasOwn(result,key)) throw Error('Duplicate key');
|
| 50 |
+
take(':'); result[key] = value(depth+1);
|
| 51 |
+
}
|
| 52 |
+
ws(); if (text[i] === end) { i++; return array ? result : {...result}; }
|
| 53 |
+
take(','); ws();
|
| 54 |
+
if (text[i] === end) { i++; return array ? result : {...result}; }
|
| 55 |
+
}
|
| 56 |
+
throw Error('Unterminated container');
|
| 57 |
+
}
|
| 58 |
+
const scalar = /^(True|False|None|true|false|null)(?![\w])/u.exec(text.slice(i));
|
| 59 |
+
if (scalar) { i += scalar[0].length; return {True:true,False:false,None:null,true:true,false:false,null:null}[scalar[0]]; }
|
| 60 |
+
const number = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/u.exec(text.slice(i));
|
| 61 |
+
if (number) { i += number[0].length; const result=Number(number[0]); if(Number.isFinite(result)) return result; }
|
| 62 |
+
throw Error('Not a literal');
|
| 63 |
+
}
|
| 64 |
+
try { const result=value(); ws(); if(i===text.length) return result; } catch { /* native strings are also unquoted */ }
|
| 65 |
+
return text;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// Strict standalone adapter. Keep downstream tool schema/approval validation in place.
|
| 69 |
+
export function parseMiniCpmToolCalls(text, toolsOrNames) {
|
| 70 |
+
const tools=Array.isArray(toolsOrNames)?toolsOrNames:[];
|
| 71 |
+
const allowedNames=Array.isArray(toolsOrNames)?new Set(tools.map(t=>t.function.name)):toolsOrNames;
|
| 72 |
+
const schemas=new Map(tools.map(t=>[t.function.name,t.function.parameters || {}]));
|
| 73 |
+
const source=String(text ?? '').trim();
|
| 74 |
+
if (!source || source.length>10000 || !(allowedNames instanceof Set)) return [];
|
| 75 |
+
// Native MiniCPM may explain an error before emitting the XML tool call.
|
| 76 |
+
// Accept that prose, but never skip over a malformed XML call or parameter.
|
| 77 |
+
const start=source.indexOf('<function');
|
| 78 |
+
if(start<0 || /<\/?(?:function|param)\b/.test(source.slice(0,start))) return [];
|
| 79 |
+
const calls=[]; let cursor=start;
|
| 80 |
+
const functions=/<function\s+name=["']([A-Za-z_]\w*)["']\s*>([\s\S]*?)<\/function>/gy;
|
| 81 |
+
const params=/<param\s+name=["']([A-Za-z_]\w*)["']\s*>([\s\S]*?)<\/param>/gy;
|
| 82 |
+
while(cursor<source.length) {
|
| 83 |
+
while (/\s/u.test(source[cursor] || '')) cursor++;
|
| 84 |
+
if(cursor===source.length) break;
|
| 85 |
+
functions.lastIndex=cursor; const fn=functions.exec(source);
|
| 86 |
+
if(!fn || !allowedNames.has(fn[1])) return [];
|
| 87 |
+
const args=Object.create(null); let pos=0;
|
| 88 |
+
while(pos<fn[2].length) {
|
| 89 |
+
while(/\s/u.test(fn[2][pos] || '')) pos++;
|
| 90 |
+
if(pos===fn[2].length) break;
|
| 91 |
+
params.lastIndex=pos; const param=params.exec(fn[2]);
|
| 92 |
+
if(!param || Object.hasOwn(args,param[1])) return [];
|
| 93 |
+
try { args[param[1]]=parseMiniCpmParamValue(param[2],schemas.get(fn[1])?.properties?.[param[1]]); }
|
| 94 |
+
catch { return []; }
|
| 95 |
+
pos=params.lastIndex;
|
| 96 |
+
}
|
| 97 |
+
calls.push({id:`compass_call_${Date.now()}_${calls.length}`,type:'function',function:{name:fn[1],arguments:JSON.stringify(args)}});
|
| 98 |
+
cursor=functions.lastIndex;
|
| 99 |
+
}
|
| 100 |
+
return calls;
|
| 101 |
+
}
|
integration/parser.test.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Portable CPU-only checks for the separately audited optional helper.
|
| 2 |
+
import test from 'node:test';
|
| 3 |
+
import assert from 'node:assert/strict';
|
| 4 |
+
import {parseMiniCpmParamValue as parse, parseMiniCpmToolCalls as calls} from './minicpm5-tool-parser.mjs';
|
| 5 |
+
|
| 6 |
+
const tools = [{type: 'function', function: {name: 'save_labels', parameters: {
|
| 7 |
+
type: 'object', properties: {labels: {type: 'array', items: {type: 'string'}}, enabled: {type: 'boolean'}},
|
| 8 |
+
}}}];
|
| 9 |
+
const xml = '<function name="save_labels"><param name="labels">[\'green\', \'amber\']</param><param name="enabled">False</param></function>';
|
| 10 |
+
|
| 11 |
+
test('v24 native list and boolean keep their argument types', () => {
|
| 12 |
+
assert.deepEqual(JSON.parse(calls(xml, tools)[0].function.arguments), {labels: ['green', 'amber'], enabled: false});
|
| 13 |
+
});
|
| 14 |
+
test('CDATA URL and string-typed JSON stay strings', () => {
|
| 15 |
+
assert.equal(parse('<![CDATA[https://example.net/find?name=blue&sort=recent]]>', {type: 'string'}), 'https://example.net/find?name=blue&sort=recent');
|
| 16 |
+
assert.equal(parse('{"message":""}', {type: 'string'}), '{"message":""}');
|
| 17 |
+
});
|
| 18 |
+
test('unknown tool names and mixed unknown batches are rejected', () => {
|
| 19 |
+
const unknown = '<function name="unprovided_tool"></function>';
|
| 20 |
+
assert.deepEqual(calls(unknown, tools), []);
|
| 21 |
+
assert.deepEqual(calls(xml + unknown, tools), []);
|
| 22 |
+
assert.deepEqual(calls(xml, []), []);
|
| 23 |
+
});
|
| 24 |
+
test('malformed and duplicate native fields are not repaired', () => {
|
| 25 |
+
assert.deepEqual(calls(xml.replace('</function>', ''), tools), []);
|
| 26 |
+
assert.deepEqual(calls(xml.replace('</function>', '<param name="enabled">True</param></function>'), tools), []);
|
| 27 |
+
assert.deepEqual(calls(xml + 'garbage', tools), []);
|
| 28 |
+
});
|
| 29 |
+
test('nested literals do not evaluate code or pollute prototypes', () => {
|
| 30 |
+
assert.deepEqual(parse("{'flag': True, 'next': None, 'xs': [1, 2.5]}"), {flag: true, next: null, xs: [1, 2.5]});
|
| 31 |
+
assert.equal(parse("['x', dangerous()]"), "['x', dangerous()]");
|
| 32 |
+
assert.equal(parse('True + exec()'), 'True + exec()');
|
| 33 |
+
parse("{'__proto__': {'polluted': True}}");
|
| 34 |
+
assert.equal(Object.prototype.polluted, undefined);
|
| 35 |
+
});
|
| 36 |
+
test('zero-argument native functions remain valid', () => {
|
| 37 |
+
const result = calls('<function name="get_accessibility_tree"></function>', new Set(['get_accessibility_tree']));
|
| 38 |
+
assert.equal(result.length, 1);
|
| 39 |
+
assert.deepEqual(JSON.parse(result[0].function.arguments), {});
|
| 40 |
+
});
|
onnx/model_q4f16.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ab10bc051ca80ad6dffe5045acac030d0d6b75c52d90db363d044f1f214fccfa
|
| 3 |
+
size 362892
|
onnx/model_q4f16.onnx_data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2abad6aebb250a04619df22e8b2cab9998ee92ba083ec5426c97ae1beb8476f7
|
| 3 |
+
size 1596739584
|
onnx/model_q4f16.onnx_data_1
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:715887fa2ce24f2f1d5f5f8adaebc0caac4bad02e7d4d90e081f85decefec244
|
| 3 |
+
size 272252928
|
runtime/inference-worker.js
ADDED
|
@@ -0,0 +1,1539 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Dedicated WebGPU worker for endpoint-free local model inference.
|
| 3 |
+
*
|
| 4 |
+
* WebGPU is unavailable in the MV3 service worker, and large ONNX allocations
|
| 5 |
+
* are more reliable in a dedicated worker than on the offscreen document's
|
| 6 |
+
* main thread. The offscreen host owns this worker and proxies correlated
|
| 7 |
+
* request/response messages to it.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
let libraryPromise = null;
|
| 11 |
+
let libraryVersion = null;
|
| 12 |
+
let workerConfig = null;
|
| 13 |
+
let visionRuntime = null;
|
| 14 |
+
let visionRuntimeKey = '';
|
| 15 |
+
let visionRuntimeModelKey = '';
|
| 16 |
+
let visionRuntimeOwner = '';
|
| 17 |
+
let visionRuntimeLoadPromise = null;
|
| 18 |
+
let visionRuntimeLoadKey = '';
|
| 19 |
+
let textRuntime = null;
|
| 20 |
+
let textRuntimeKey = '';
|
| 21 |
+
let textRuntimeModelKey = '';
|
| 22 |
+
let textRuntimeLoadPromise = null;
|
| 23 |
+
let textRuntimeLoadKey = '';
|
| 24 |
+
let modelOperationQueue = Promise.resolve();
|
| 25 |
+
const TRANSFORMERS_CACHE_NAME = 'transformers-cache';
|
| 26 |
+
const TEXT_DOWNLOAD_EVENT = 'text-download-state';
|
| 27 |
+
const WEBGPU_TEXT_MAX_NEW_TOKENS = 256;
|
| 28 |
+
const WEBGPU_LFM25_MODEL_ID = 'LiquidAI/LFM2.5-2.6B-ONNX';
|
| 29 |
+
const WEBGPU_LFM25_12B_INSTRUCT_MODEL_ID = 'LiquidAI/LFM2.5-1.2B-Instruct-ONNX';
|
| 30 |
+
const WEBGPU_LFM25_12B_THINKING_MODEL_ID = 'LiquidAI/LFM2.5-1.2B-Thinking-ONNX';
|
| 31 |
+
const WEBGPU_LFM25_VL_16B_MODEL_ID = 'LiquidAI/LFM2.5-VL-1.6B-ONNX';
|
| 32 |
+
const WEBGPU_LFM25_VL_3B_MODEL_ID = 'LiquidAI/LFM2.5-VL-3B-ONNX';
|
| 33 |
+
const WEBGPU_NANBEIGE42_3B_MODEL_ID = 'Michionlion/Nanbeige4.2-3B-ONNX-WebGPU';
|
| 34 |
+
const WEBGPU_MINICPM5_2B_MODEL_ID = 'RASMUS/MiniCPM5-2B-ONNX';
|
| 35 |
+
const WEBGPU_BONSAI27_MODEL_ID = 'prism-ml/Bonsai-27B-gguf';
|
| 36 |
+
const WEBGPU_LFM25_MAX_NEW_TOKENS = 2048;
|
| 37 |
+
const WEBGPU_LFM25_TEXT_MODEL_IDS = new Set([
|
| 38 |
+
WEBGPU_LFM25_MODEL_ID,
|
| 39 |
+
WEBGPU_LFM25_12B_INSTRUCT_MODEL_ID,
|
| 40 |
+
WEBGPU_LFM25_12B_THINKING_MODEL_ID,
|
| 41 |
+
]);
|
| 42 |
+
const WEBGPU_LFM25_VL_MODEL_IDS = new Set([
|
| 43 |
+
WEBGPU_LFM25_VL_16B_MODEL_ID,
|
| 44 |
+
WEBGPU_LFM25_VL_3B_MODEL_ID,
|
| 45 |
+
]);
|
| 46 |
+
// Presets whose reasoning is generated as hidden thinking rather than as part
|
| 47 |
+
// of the visible answer, so they need the long output budget.
|
| 48 |
+
const WEBGPU_REASONING_MODEL_IDS = new Set([
|
| 49 |
+
WEBGPU_LFM25_MODEL_ID,
|
| 50 |
+
WEBGPU_LFM25_12B_THINKING_MODEL_ID,
|
| 51 |
+
WEBGPU_NANBEIGE42_3B_MODEL_ID,
|
| 52 |
+
WEBGPU_MINICPM5_2B_MODEL_ID,
|
| 53 |
+
]);
|
| 54 |
+
// Chat templates that emit the opening `<think>` themselves, so the runtime
|
| 55 |
+
// only returns the reasoning suffix.
|
| 56 |
+
const WEBGPU_OPEN_THINKING_MODEL_IDS = new Set([
|
| 57 |
+
WEBGPU_LFM25_MODEL_ID,
|
| 58 |
+
WEBGPU_NANBEIGE42_3B_MODEL_ID,
|
| 59 |
+
]);
|
| 60 |
+
const WEBGPU_LONG_OUTPUT_MODEL_IDS = new Set([
|
| 61 |
+
...WEBGPU_LFM25_TEXT_MODEL_IDS,
|
| 62 |
+
WEBGPU_NANBEIGE42_3B_MODEL_ID,
|
| 63 |
+
WEBGPU_MINICPM5_2B_MODEL_ID,
|
| 64 |
+
]);
|
| 65 |
+
// Publisher-recommended decoding for the shipped reasoning presets. Custom
|
| 66 |
+
// repositories keep Transformers.js greedy defaults.
|
| 67 |
+
const WEBGPU_TEXT_SAMPLING = new Map([
|
| 68 |
+
[WEBGPU_LFM25_MODEL_ID, { temperature: 0.1, top_k: 50, repetition_penalty: 1.1 }],
|
| 69 |
+
[WEBGPU_LFM25_12B_THINKING_MODEL_ID, { temperature: 0.05, top_k: 50, repetition_penalty: 1.05 }],
|
| 70 |
+
// Nanbeige4.2-3B's own generation_config.json.
|
| 71 |
+
[WEBGPU_NANBEIGE42_3B_MODEL_ID, { temperature: 0.6, top_k: 20, top_p: 0.95 }],
|
| 72 |
+
// MiniCPM5-2B quickstart: temperature=1.0, top_p=0.95.
|
| 73 |
+
[WEBGPU_MINICPM5_2B_MODEL_ID, { temperature: 1.0, top_p: 0.95 }],
|
| 74 |
+
]);
|
| 75 |
+
// Nanbeige ships a single WebGPU-fused graph under a non-default file name.
|
| 76 |
+
// Without this override Transformers.js looks for `onnx/model_q4f16.onnx`,
|
| 77 |
+
// which the repository does not publish.
|
| 78 |
+
const WEBGPU_TEXT_MODEL_FILE_NAMES = new Map([
|
| 79 |
+
[WEBGPU_NANBEIGE42_3B_MODEL_ID, 'model_webgpu_mlp'],
|
| 80 |
+
]);
|
| 81 |
+
const WEBGPU_VISION_READY_MARKER_VERSION = 2;
|
| 82 |
+
const WEBGPU_VISION_READY_MARKER_PREFIX = 'https://webbrain.one/.well-known/webgpu-vision-ready/';
|
| 83 |
+
function createWebGpuTextSessionOptions() {
|
| 84 |
+
return {
|
| 85 |
+
extra: {
|
| 86 |
+
// ORT's default bucket cache can retain rounded-up transient buffers. That
|
| 87 |
+
// is especially costly for dynamic prefill/decode shapes on Metal.
|
| 88 |
+
'ep.webgpuexecutionprovider.storageBufferCacheMode': 'simple',
|
| 89 |
+
},
|
| 90 |
+
};
|
| 91 |
+
}
|
| 92 |
+
const readyTextModelKeys = new Set();
|
| 93 |
+
const textDownloadFiles = new Map();
|
| 94 |
+
const nativeFetch = typeof globalThis.fetch === 'function' ? globalThis.fetch.bind(globalThis) : null;
|
| 95 |
+
let activeTextDownloadModelId = '';
|
| 96 |
+
let queuedTextDownload = null;
|
| 97 |
+
let textDownloadAbortController = null;
|
| 98 |
+
let textDownloadCancelMode = '';
|
| 99 |
+
let activeVisionDownloadRequest = null;
|
| 100 |
+
let queuedVisionDownload = null;
|
| 101 |
+
let visionDownloadAbortController = null;
|
| 102 |
+
const activeVisionGenerations = new Map();
|
| 103 |
+
const queuedVisionGenerations = new Set();
|
| 104 |
+
const cancelledVisionGenerations = new Set();
|
| 105 |
+
let lastTextProgressPostAt = 0;
|
| 106 |
+
let webGpuAdapterProbePromise = null;
|
| 107 |
+
let webGpuAdapterSummary = '';
|
| 108 |
+
let observedWebGpuDevice = null;
|
| 109 |
+
let lastWebGpuDeviceError = '';
|
| 110 |
+
let lastWebGpuDeviceLost = '';
|
| 111 |
+
let textDownloadState = {
|
| 112 |
+
status: 'not-downloaded',
|
| 113 |
+
ready: false,
|
| 114 |
+
modelId: '',
|
| 115 |
+
dtype: '',
|
| 116 |
+
file: '',
|
| 117 |
+
loaded: 0,
|
| 118 |
+
total: 0,
|
| 119 |
+
progress: 0,
|
| 120 |
+
error: '',
|
| 121 |
+
};
|
| 122 |
+
|
| 123 |
+
function textDtypeKey(dtype) {
|
| 124 |
+
if (!dtype || typeof dtype !== 'object' || Array.isArray(dtype)) return String(dtype || '').trim();
|
| 125 |
+
return JSON.stringify(Object.fromEntries(
|
| 126 |
+
Object.entries(dtype).sort(([left], [right]) => left.localeCompare(right)),
|
| 127 |
+
));
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
function textModelKey(modelId, dtype) {
|
| 131 |
+
return `${String(modelId || '').trim()}|${textDtypeKey(dtype)}`;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
function sameTextModel(leftModelId, leftDtype, rightModelId, rightDtype) {
|
| 135 |
+
return textModelKey(leftModelId, leftDtype) === textModelKey(rightModelId, rightDtype);
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
function assertOnnxTextModel(modelId) {
|
| 139 |
+
const normalized = String(modelId || '').trim();
|
| 140 |
+
if (!normalized) throw new Error('No text-generation model was specified.');
|
| 141 |
+
if (normalized === WEBGPU_BONSAI27_MODEL_ID || /\.gguf$/i.test(normalized)) {
|
| 142 |
+
throw new Error(`${normalized} is a GGUF checkpoint and cannot be loaded with Transformers.js. Use the Bonsai WebGPU runtime.`);
|
| 143 |
+
}
|
| 144 |
+
return normalized;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
function isLfm25VlModel(modelId) {
|
| 148 |
+
return WEBGPU_LFM25_VL_MODEL_IDS.has(String(modelId || '').trim());
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
function lfm25VlProcessorOptions(modelId) {
|
| 152 |
+
if (!isLfm25VlModel(modelId)) return {};
|
| 153 |
+
return {
|
| 154 |
+
// LiquidAI's current VL ONNX repos use the Transformers v5 layout: image
|
| 155 |
+
// settings are nested in processor_config.json and the chat template is a
|
| 156 |
+
// separate Jinja file. The packaged Transformers.js 4.2 runtime supports
|
| 157 |
+
// both through WebBrain's documented browser-bundle compatibility hooks.
|
| 158 |
+
image_processor_config_file: 'processor_config.json',
|
| 159 |
+
chat_template_file: 'chat_template.jinja',
|
| 160 |
+
};
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
function assertTextDownloadCanStart(payload) {
|
| 164 |
+
const modelId = assertOnnxTextModel(payload?.modelId);
|
| 165 |
+
const dtype = payload?.dtype || 'q4f16';
|
| 166 |
+
const conflictsWithTransfer = textDownloadState.modelId
|
| 167 |
+
&& !sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype)
|
| 168 |
+
&& ['downloading', 'paused', 'stopping'].includes(textDownloadState.status);
|
| 169 |
+
const conflictsWithQueued = queuedTextDownload
|
| 170 |
+
&& !sameTextModel(queuedTextDownload.modelId, queuedTextDownload.dtype, modelId, dtype);
|
| 171 |
+
if (conflictsWithTransfer || conflictsWithQueued) {
|
| 172 |
+
const blockingModel = conflictsWithTransfer ? textDownloadState.modelId : queuedTextDownload.modelId;
|
| 173 |
+
throw new Error(`Finish or stop the ${blockingModel} download before downloading ${modelId}.`);
|
| 174 |
+
}
|
| 175 |
+
return { modelId, dtype, key: textModelKey(modelId, dtype) };
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
function textReadyMarkerUrl(modelId, dtype) {
|
| 179 |
+
const key = encodeURIComponent(textModelKey(modelId, dtype));
|
| 180 |
+
return `https://webbrain.one/.well-known/webgpu-model-ready/${key}`;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
function safeDecodedUrl(value) {
|
| 184 |
+
try { return decodeURIComponent(String(value || '')); } catch { return String(value || ''); }
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
function fetchTargetsActiveTextModel(input) {
|
| 188 |
+
if (!activeTextDownloadModelId) return false;
|
| 189 |
+
const url = typeof input === 'string' || input instanceof URL ? String(input) : input?.url;
|
| 190 |
+
return safeDecodedUrl(url).includes(`/${activeTextDownloadModelId}/`);
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
function fetchTargetsActiveVisionModel(input) {
|
| 194 |
+
if (!activeVisionDownloadRequest?.modelId) return false;
|
| 195 |
+
const url = typeof input === 'string' || input instanceof URL ? String(input) : input?.url;
|
| 196 |
+
return safeDecodedUrl(url).includes(`/${activeVisionDownloadRequest.modelId}/`);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
function visionReadyMarkerUrl(modelId) {
|
| 200 |
+
return `${WEBGPU_VISION_READY_MARKER_PREFIX}v${WEBGPU_VISION_READY_MARKER_VERSION}/${encodeURIComponent(String(modelId || '').trim())}`;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
function isVisionReadyMarkerForModel(url, modelId) {
|
| 204 |
+
const candidate = String(url || '');
|
| 205 |
+
const encodedModelId = encodeURIComponent(String(modelId || '').trim());
|
| 206 |
+
return candidate.startsWith(WEBGPU_VISION_READY_MARKER_PREFIX)
|
| 207 |
+
&& candidate.endsWith(`/${encodedModelId}`);
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
async function isVisionModelCached(modelId) {
|
| 211 |
+
const normalized = String(modelId || '').trim();
|
| 212 |
+
if (!normalized) return false;
|
| 213 |
+
if (typeof caches === 'undefined') return null;
|
| 214 |
+
const markerUrl = visionReadyMarkerUrl(normalized);
|
| 215 |
+
try {
|
| 216 |
+
for (const name of await caches.keys()) {
|
| 217 |
+
if (!/transformers/i.test(name)) continue;
|
| 218 |
+
const cache = await caches.open(name);
|
| 219 |
+
if (await cache.match(markerUrl)) return true;
|
| 220 |
+
}
|
| 221 |
+
} catch {
|
| 222 |
+
return null;
|
| 223 |
+
}
|
| 224 |
+
return false;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
async function markVisionModelReady(modelId) {
|
| 228 |
+
const normalized = String(modelId || '').trim();
|
| 229 |
+
if (!normalized || typeof caches === 'undefined') return;
|
| 230 |
+
const cache = await caches.open(TRANSFORMERS_CACHE_NAME);
|
| 231 |
+
await cache.put(visionReadyMarkerUrl(normalized), new Response(JSON.stringify({
|
| 232 |
+
modelId: normalized,
|
| 233 |
+
markerVersion: WEBGPU_VISION_READY_MARKER_VERSION,
|
| 234 |
+
}), {
|
| 235 |
+
headers: { 'content-type': 'application/json' },
|
| 236 |
+
}));
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
async function controlledFetch(input, init = {}) {
|
| 240 |
+
if (!nativeFetch) throw new Error('Fetch is unavailable in the WebGPU worker.');
|
| 241 |
+
if (textDownloadAbortController && fetchTargetsActiveTextModel(input)) {
|
| 242 |
+
return nativeFetch(input, { ...init, signal: textDownloadAbortController.signal });
|
| 243 |
+
}
|
| 244 |
+
if (visionDownloadAbortController && fetchTargetsActiveVisionModel(input)) {
|
| 245 |
+
return nativeFetch(input, { ...init, signal: visionDownloadAbortController.signal });
|
| 246 |
+
}
|
| 247 |
+
return nativeFetch(input, init);
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
function textDownloadSnapshot() {
|
| 251 |
+
return { ...textDownloadState };
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
function postTextDownloadState({ force = false } = {}) {
|
| 255 |
+
const now = Date.now();
|
| 256 |
+
if (!force && now - lastTextProgressPostAt < 160) return;
|
| 257 |
+
lastTextProgressPostAt = now;
|
| 258 |
+
self.postMessage({ type: TEXT_DOWNLOAD_EVENT, state: textDownloadSnapshot() });
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
async function isTextModelReady(modelId, dtype) {
|
| 262 |
+
const key = textModelKey(modelId, dtype);
|
| 263 |
+
if (readyTextModelKeys.has(key)) return true;
|
| 264 |
+
if (typeof caches === 'undefined') return false;
|
| 265 |
+
try {
|
| 266 |
+
const cache = await caches.open(TRANSFORMERS_CACHE_NAME);
|
| 267 |
+
const marker = await cache.match(textReadyMarkerUrl(modelId, dtype));
|
| 268 |
+
if (!marker) return false;
|
| 269 |
+
readyTextModelKeys.add(key);
|
| 270 |
+
return true;
|
| 271 |
+
} catch {
|
| 272 |
+
return false;
|
| 273 |
+
}
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
async function markTextModelReady(modelId, dtype) {
|
| 277 |
+
const key = textModelKey(modelId, dtype);
|
| 278 |
+
if (typeof caches === 'undefined') {
|
| 279 |
+
readyTextModelKeys.add(key);
|
| 280 |
+
return;
|
| 281 |
+
}
|
| 282 |
+
const cache = await caches.open(TRANSFORMERS_CACHE_NAME);
|
| 283 |
+
await cache.put(textReadyMarkerUrl(modelId, dtype), new Response(JSON.stringify({ modelId, dtype }), {
|
| 284 |
+
headers: { 'content-type': 'application/json' },
|
| 285 |
+
}));
|
| 286 |
+
readyTextModelKeys.add(key);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
async function loadLibrary() {
|
| 290 |
+
if (libraryPromise) return libraryPromise;
|
| 291 |
+
if (!workerConfig) throw new Error('WebGPU worker was not initialized.');
|
| 292 |
+
libraryPromise = (async () => {
|
| 293 |
+
let library;
|
| 294 |
+
try {
|
| 295 |
+
library = await import(workerConfig.transformersUrl);
|
| 296 |
+
} catch (error) {
|
| 297 |
+
libraryPromise = null;
|
| 298 |
+
throw new Error(`The packaged Transformers.js runtime could not be loaded: ${error?.message || error}`);
|
| 299 |
+
}
|
| 300 |
+
libraryVersion = library.env?.version || library.VERSION || 'unknown';
|
| 301 |
+
if (library.env) {
|
| 302 |
+
library.env.allowLocalModels = false;
|
| 303 |
+
library.env.allowRemoteModels = true;
|
| 304 |
+
library.env.useBrowserCache = true;
|
| 305 |
+
library.env.useWasmCache = false;
|
| 306 |
+
library.env.fetch = controlledFetch;
|
| 307 |
+
const wasm = library.env.backends?.onnx?.wasm;
|
| 308 |
+
if (wasm) {
|
| 309 |
+
wasm.numThreads = 1;
|
| 310 |
+
wasm.wasmPaths = {
|
| 311 |
+
mjs: workerConfig.wasmMjsUrl,
|
| 312 |
+
wasm: workerConfig.wasmUrl,
|
| 313 |
+
};
|
| 314 |
+
}
|
| 315 |
+
}
|
| 316 |
+
return library;
|
| 317 |
+
})();
|
| 318 |
+
return libraryPromise;
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
function compactAdapterInfo(adapter) {
|
| 322 |
+
if (!adapter) return '';
|
| 323 |
+
const info = adapter.info || {};
|
| 324 |
+
const identity = [info.vendor, info.architecture, info.device, info.description]
|
| 325 |
+
.map(value => String(value || '').trim())
|
| 326 |
+
.filter((value, index, values) => value && values.indexOf(value) === index)
|
| 327 |
+
.join(' / ');
|
| 328 |
+
const maxBufferSize = Number(adapter.limits?.maxBufferSize);
|
| 329 |
+
const maxStorageBinding = Number(adapter.limits?.maxStorageBufferBindingSize);
|
| 330 |
+
const limits = [
|
| 331 |
+
Number.isFinite(maxBufferSize) ? `maxBufferSize=${maxBufferSize}` : '',
|
| 332 |
+
Number.isFinite(maxStorageBinding) ? `maxStorageBufferBindingSize=${maxStorageBinding}` : '',
|
| 333 |
+
].filter(Boolean).join(', ');
|
| 334 |
+
return [identity, limits].filter(Boolean).join('; ');
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
async function captureWebGpuAdapterSummary() {
|
| 338 |
+
if (webGpuAdapterProbePromise) return webGpuAdapterProbePromise;
|
| 339 |
+
webGpuAdapterProbePromise = (async () => {
|
| 340 |
+
if (typeof navigator === 'undefined' || !navigator.gpu) return '';
|
| 341 |
+
try {
|
| 342 |
+
const adapter = await navigator.gpu.requestAdapter({ powerPreference: 'high-performance' });
|
| 343 |
+
webGpuAdapterSummary = compactAdapterInfo(adapter);
|
| 344 |
+
} catch {}
|
| 345 |
+
return webGpuAdapterSummary;
|
| 346 |
+
})();
|
| 347 |
+
return webGpuAdapterProbePromise;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
function bindWebGpuDeviceDiagnostics(library) {
|
| 351 |
+
const device = library?.env?.backends?.onnx?.webgpu?.device;
|
| 352 |
+
if (!device || device === observedWebGpuDevice) return;
|
| 353 |
+
observedWebGpuDevice = device;
|
| 354 |
+
lastWebGpuDeviceError = '';
|
| 355 |
+
lastWebGpuDeviceLost = '';
|
| 356 |
+
device.addEventListener?.('uncapturederror', event => {
|
| 357 |
+
lastWebGpuDeviceError = String(event?.error?.message || event?.message || 'Unknown WebGPU validation error.');
|
| 358 |
+
console.error('[webgpu] uncaptured device error:', lastWebGpuDeviceError);
|
| 359 |
+
});
|
| 360 |
+
device.lost?.then(info => {
|
| 361 |
+
if (device !== observedWebGpuDevice) return;
|
| 362 |
+
lastWebGpuDeviceLost = String(info?.message || info?.reason || 'The WebGPU device was lost.');
|
| 363 |
+
console.error('[webgpu] device lost:', lastWebGpuDeviceLost);
|
| 364 |
+
}).catch(() => {});
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
function isWebGpuExecutionFailure(error) {
|
| 368 |
+
return /OrtRun|BufferManager::Download|mapAsync|GPUBuffer|device lost/i.test(error?.message || String(error));
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
async function enrichWebGpuExecutionError(error) {
|
| 372 |
+
// WebGPU uncaptured-error/device-lost events can arrive just after OrtRun's
|
| 373 |
+
// generic buffer readback exception. Give that event one task to land so the
|
| 374 |
+
// user sees the actionable root error instead of only "Invalid Buffer".
|
| 375 |
+
await new Promise(resolve => setTimeout(resolve, 0));
|
| 376 |
+
const details = [lastWebGpuDeviceError, lastWebGpuDeviceLost]
|
| 377 |
+
.map(value => String(value || '').trim())
|
| 378 |
+
.filter((value, index, values) => value && values.indexOf(value) === index);
|
| 379 |
+
const adapter = webGpuAdapterSummary || await captureWebGpuAdapterSummary();
|
| 380 |
+
const suffix = [
|
| 381 |
+
details.length ? `GPU detail: ${details.join(' ')}` : '',
|
| 382 |
+
adapter ? `Adapter: ${adapter}.` : '',
|
| 383 |
+
'Close other GPU-heavy tabs/apps and retry with a short prompt. If it persists, this GPU/driver cannot execute this model with the current WebGPU runtime.',
|
| 384 |
+
].filter(Boolean).join(' ');
|
| 385 |
+
return new Error(`${error?.message || String(error)} ${suffix}`);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
function postProgress(modelId, event) {
|
| 389 |
+
if (modelId === activeTextDownloadModelId && !textDownloadCancelMode) {
|
| 390 |
+
const file = String(event?.file || event?.name || '');
|
| 391 |
+
if (file) {
|
| 392 |
+
const previous = textDownloadFiles.get(file) || { loaded: 0, total: 0, status: '' };
|
| 393 |
+
const total = Number(event?.total || previous.total || 0);
|
| 394 |
+
const loaded = event?.status === 'done' && total > 0
|
| 395 |
+
? total
|
| 396 |
+
: Number(event?.loaded ?? previous.loaded ?? 0);
|
| 397 |
+
textDownloadFiles.set(file, {
|
| 398 |
+
status: event?.status || previous.status,
|
| 399 |
+
loaded: Math.max(0, loaded),
|
| 400 |
+
total: Math.max(0, total),
|
| 401 |
+
});
|
| 402 |
+
}
|
| 403 |
+
let loaded = 0;
|
| 404 |
+
let total = 0;
|
| 405 |
+
for (const item of textDownloadFiles.values()) {
|
| 406 |
+
if (item.total <= 0) continue;
|
| 407 |
+
loaded += Math.min(item.loaded, item.total);
|
| 408 |
+
total += item.total;
|
| 409 |
+
}
|
| 410 |
+
textDownloadState = {
|
| 411 |
+
...textDownloadState,
|
| 412 |
+
status: 'downloading',
|
| 413 |
+
ready: false,
|
| 414 |
+
file,
|
| 415 |
+
loaded,
|
| 416 |
+
total,
|
| 417 |
+
progress: total > 0 ? Math.max(0, Math.min(100, loaded / total * 100)) : 0,
|
| 418 |
+
error: '',
|
| 419 |
+
};
|
| 420 |
+
postTextDownloadState({ force: event?.status === 'done' });
|
| 421 |
+
}
|
| 422 |
+
self.postMessage({
|
| 423 |
+
type: 'progress',
|
| 424 |
+
modelId,
|
| 425 |
+
status: event?.status || '',
|
| 426 |
+
file: event?.file || event?.name || '',
|
| 427 |
+
loaded: Number(event?.loaded || 0),
|
| 428 |
+
total: Number(event?.total || 0),
|
| 429 |
+
progress: Number(event?.progress || 0),
|
| 430 |
+
});
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
async function disposeRuntime(runtime) {
|
| 434 |
+
if (runtime?.pipeline?.dispose) {
|
| 435 |
+
try { await runtime.pipeline.dispose(); } catch {}
|
| 436 |
+
} else if (runtime?.model?.dispose) {
|
| 437 |
+
try { await runtime.model.dispose(); } catch {}
|
| 438 |
+
}
|
| 439 |
+
if (runtime?.processor?.dispose) {
|
| 440 |
+
try { await runtime.processor.dispose(); } catch {}
|
| 441 |
+
}
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
async function disposeVisionRuntime(expectedOwner = '') {
|
| 445 |
+
if (expectedOwner && visionRuntimeOwner && visionRuntimeOwner !== expectedOwner) return;
|
| 446 |
+
const runtime = visionRuntime;
|
| 447 |
+
visionRuntime = null;
|
| 448 |
+
visionRuntimeKey = '';
|
| 449 |
+
visionRuntimeModelKey = '';
|
| 450 |
+
visionRuntimeOwner = '';
|
| 451 |
+
await disposeRuntime(runtime);
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
async function disposeTextRuntime() {
|
| 455 |
+
const runtime = textRuntime;
|
| 456 |
+
textRuntime = null;
|
| 457 |
+
textRuntimeKey = '';
|
| 458 |
+
textRuntimeModelKey = '';
|
| 459 |
+
await disposeRuntime(runtime);
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
async function disposeAllRuntimes() {
|
| 463 |
+
await disposeVisionRuntime();
|
| 464 |
+
await disposeTextRuntime();
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
async function legacyLfm25VlConfig(library, modelId, progress_callback, localFilesOnly) {
|
| 468 |
+
if (modelId !== WEBGPU_LFM25_VL_16B_MODEL_ID) return null;
|
| 469 |
+
if (!library.AutoConfig) {
|
| 470 |
+
throw new Error('The packaged Transformers.js version cannot load the LFM2.5-VL-1.6B model config.');
|
| 471 |
+
}
|
| 472 |
+
const config = await library.AutoConfig.from_pretrained(modelId, {
|
| 473 |
+
progress_callback,
|
| 474 |
+
local_files_only: localFilesOnly,
|
| 475 |
+
});
|
| 476 |
+
config['transformers.js_config'] = {
|
| 477 |
+
...(config['transformers.js_config'] || {}),
|
| 478 |
+
// LiquidAI's 1.6B ONNX export predates the standard Transformers.js
|
| 479 |
+
// ImageTextToText filenames used by the newer 3B package.
|
| 480 |
+
session_file_names: {
|
| 481 |
+
embed_tokens: 'embed_tokens',
|
| 482 |
+
vision_encoder: 'embed_images',
|
| 483 |
+
decoder_model_merged: 'decoder',
|
| 484 |
+
},
|
| 485 |
+
use_external_data_format: {
|
| 486 |
+
'embed_tokens_fp16.onnx': 1,
|
| 487 |
+
'embed_images_fp16.onnx': 1,
|
| 488 |
+
'decoder_q4.onnx': 1,
|
| 489 |
+
},
|
| 490 |
+
};
|
| 491 |
+
return config;
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
async function getVisionRuntime(modelId, dtype, device, {
|
| 495 |
+
localFilesOnly = false,
|
| 496 |
+
owner = 'vision',
|
| 497 |
+
readiness = 'vision',
|
| 498 |
+
} = {}) {
|
| 499 |
+
const key = `vision|${modelId}|${device}|${JSON.stringify(dtype)}`;
|
| 500 |
+
if (visionRuntime && visionRuntimeKey === key) {
|
| 501 |
+
visionRuntimeOwner = owner;
|
| 502 |
+
return visionRuntime;
|
| 503 |
+
}
|
| 504 |
+
if (visionRuntimeLoadPromise) {
|
| 505 |
+
if (visionRuntimeLoadKey === key) return visionRuntimeLoadPromise;
|
| 506 |
+
await visionRuntimeLoadPromise.catch(() => {});
|
| 507 |
+
if (visionRuntime && visionRuntimeKey === key) {
|
| 508 |
+
visionRuntimeOwner = owner;
|
| 509 |
+
return visionRuntime;
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
const loadPromise = (async () => {
|
| 514 |
+
const locallyReady = readiness === 'text'
|
| 515 |
+
? await isTextModelReady(modelId, dtype)
|
| 516 |
+
: await isVisionModelCached(modelId);
|
| 517 |
+
if (localFilesOnly && locallyReady === false) {
|
| 518 |
+
const error = new Error(`${modelId} is not cached locally.`);
|
| 519 |
+
error.code = readiness === 'text' ? 'text_model_not_downloaded' : 'vision_model_not_downloaded';
|
| 520 |
+
throw error;
|
| 521 |
+
}
|
| 522 |
+
const library = await loadLibrary();
|
| 523 |
+
const { AutoModelForImageTextToText, AutoProcessor } = library;
|
| 524 |
+
if (!AutoModelForImageTextToText || !AutoProcessor) {
|
| 525 |
+
throw new Error('The packaged Transformers.js version does not include image-text-to-text support.');
|
| 526 |
+
}
|
| 527 |
+
if (owner === 'text') await disposeTextRuntime();
|
| 528 |
+
await disposeVisionRuntime();
|
| 529 |
+
const progress_callback = event => postProgress(modelId, event);
|
| 530 |
+
const config = await legacyLfm25VlConfig(library, modelId, progress_callback, localFilesOnly);
|
| 531 |
+
const processorOptions = lfm25VlProcessorOptions(modelId);
|
| 532 |
+
const previousAllowLocalModels = library.env?.allowLocalModels;
|
| 533 |
+
if (localFilesOnly && library.env) library.env.allowLocalModels = true;
|
| 534 |
+
let processorResult;
|
| 535 |
+
let modelResult;
|
| 536 |
+
try {
|
| 537 |
+
[processorResult, modelResult] = await Promise.allSettled([
|
| 538 |
+
AutoProcessor.from_pretrained(modelId, {
|
| 539 |
+
...processorOptions,
|
| 540 |
+
progress_callback,
|
| 541 |
+
local_files_only: localFilesOnly,
|
| 542 |
+
}),
|
| 543 |
+
AutoModelForImageTextToText.from_pretrained(modelId, {
|
| 544 |
+
device,
|
| 545 |
+
dtype,
|
| 546 |
+
...(config ? { config } : {}),
|
| 547 |
+
progress_callback,
|
| 548 |
+
local_files_only: localFilesOnly,
|
| 549 |
+
}),
|
| 550 |
+
]);
|
| 551 |
+
} finally {
|
| 552 |
+
if (localFilesOnly && library.env) library.env.allowLocalModels = previousAllowLocalModels;
|
| 553 |
+
}
|
| 554 |
+
if (processorResult.status === 'rejected' || modelResult.status === 'rejected') {
|
| 555 |
+
const loaded = [processorResult, modelResult]
|
| 556 |
+
.filter(result => result.status === 'fulfilled')
|
| 557 |
+
.map(result => result.value);
|
| 558 |
+
for (const resource of loaded) {
|
| 559 |
+
if (resource?.dispose) {
|
| 560 |
+
try { await resource.dispose(); } catch {}
|
| 561 |
+
}
|
| 562 |
+
}
|
| 563 |
+
throw processorResult.status === 'rejected'
|
| 564 |
+
? processorResult.reason
|
| 565 |
+
: modelResult.reason;
|
| 566 |
+
}
|
| 567 |
+
const processor = processorResult.value;
|
| 568 |
+
const model = modelResult.value;
|
| 569 |
+
visionRuntime = { library, processor, model };
|
| 570 |
+
visionRuntimeKey = key;
|
| 571 |
+
visionRuntimeModelKey = textModelKey(modelId, dtype);
|
| 572 |
+
visionRuntimeOwner = owner;
|
| 573 |
+
return visionRuntime;
|
| 574 |
+
})();
|
| 575 |
+
visionRuntimeLoadPromise = loadPromise;
|
| 576 |
+
visionRuntimeLoadKey = key;
|
| 577 |
+
try {
|
| 578 |
+
return await loadPromise;
|
| 579 |
+
} finally {
|
| 580 |
+
if (visionRuntimeLoadPromise === loadPromise) {
|
| 581 |
+
visionRuntimeLoadPromise = null;
|
| 582 |
+
visionRuntimeLoadKey = '';
|
| 583 |
+
}
|
| 584 |
+
}
|
| 585 |
+
}
|
| 586 |
+
|
| 587 |
+
async function preloadRuntime(payload = {}) {
|
| 588 |
+
const modelId = String(payload.modelId || '').trim();
|
| 589 |
+
if (!modelId) throw new Error('No vision model was specified.');
|
| 590 |
+
const device = payload.device || 'webgpu';
|
| 591 |
+
const dtype = payload.dtype || {
|
| 592 |
+
embed_tokens: 'fp16',
|
| 593 |
+
vision_encoder: 'fp16',
|
| 594 |
+
decoder_model_merged: 'q4',
|
| 595 |
+
};
|
| 596 |
+
await getVisionRuntime(modelId, dtype, device);
|
| 597 |
+
await disposeVisionRuntime();
|
| 598 |
+
return modelId;
|
| 599 |
+
}
|
| 600 |
+
|
| 601 |
+
function visionDownloadState(request, status) {
|
| 602 |
+
return {
|
| 603 |
+
status,
|
| 604 |
+
ready: status === 'ready',
|
| 605 |
+
modelId: request?.modelId || '',
|
| 606 |
+
dtype: request?.dtype || '',
|
| 607 |
+
};
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
async function preloadVisionModel(payload, request) {
|
| 611 |
+
if (queuedVisionDownload !== request || request.cancelMode) {
|
| 612 |
+
return visionDownloadState(request, request.cancelMode === 'stop' ? 'not-downloaded' : 'paused');
|
| 613 |
+
}
|
| 614 |
+
queuedVisionDownload = null;
|
| 615 |
+
activeVisionDownloadRequest = request;
|
| 616 |
+
const controller = new AbortController();
|
| 617 |
+
visionDownloadAbortController = controller;
|
| 618 |
+
try {
|
| 619 |
+
await preloadRuntime(payload);
|
| 620 |
+
const status = request.cancelMode === 'stop'
|
| 621 |
+
? 'not-downloaded'
|
| 622 |
+
: request.cancelMode === 'pause' ? 'paused' : 'ready';
|
| 623 |
+
if (status === 'ready') await markVisionModelReady(request.modelId);
|
| 624 |
+
return visionDownloadState(request, status);
|
| 625 |
+
} catch (error) {
|
| 626 |
+
if (request.cancelMode || controller.signal.aborted) {
|
| 627 |
+
return visionDownloadState(request, request.cancelMode === 'stop' ? 'not-downloaded' : 'paused');
|
| 628 |
+
}
|
| 629 |
+
throw error;
|
| 630 |
+
} finally {
|
| 631 |
+
if (visionDownloadAbortController === controller) visionDownloadAbortController = null;
|
| 632 |
+
if (activeVisionDownloadRequest === request) activeVisionDownloadRequest = null;
|
| 633 |
+
}
|
| 634 |
+
}
|
| 635 |
+
|
| 636 |
+
function pauseVisionDownload(modelId) {
|
| 637 |
+
const normalizedModelId = String(modelId || '').trim();
|
| 638 |
+
const queued = queuedVisionDownload;
|
| 639 |
+
const active = activeVisionDownloadRequest;
|
| 640 |
+
const targetQueued = queued && (!normalizedModelId || queued.modelId === normalizedModelId);
|
| 641 |
+
const targetActive = active && (!normalizedModelId || active.modelId === normalizedModelId);
|
| 642 |
+
if (targetQueued) {
|
| 643 |
+
queued.cancelMode = 'pause';
|
| 644 |
+
if (queuedVisionDownload === queued) queuedVisionDownload = null;
|
| 645 |
+
}
|
| 646 |
+
if (targetActive) {
|
| 647 |
+
active.cancelMode = 'pause';
|
| 648 |
+
visionDownloadAbortController?.abort();
|
| 649 |
+
}
|
| 650 |
+
const target = targetActive ? active : targetQueued ? queued : { modelId: normalizedModelId };
|
| 651 |
+
return {
|
| 652 |
+
...visionDownloadState(target, 'paused'),
|
| 653 |
+
targetsQueued: Boolean(targetQueued),
|
| 654 |
+
targetsActive: Boolean(targetActive),
|
| 655 |
+
};
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
function stopVisionDownload(modelId) {
|
| 659 |
+
const normalizedModelId = String(modelId || '').trim();
|
| 660 |
+
const queued = queuedVisionDownload;
|
| 661 |
+
const active = activeVisionDownloadRequest;
|
| 662 |
+
const targetsQueued = Boolean(queued && (!normalizedModelId || queued.modelId === normalizedModelId));
|
| 663 |
+
const targetsActive = Boolean(active && (!normalizedModelId || active.modelId === normalizedModelId));
|
| 664 |
+
if (targetsQueued) {
|
| 665 |
+
queued.cancelMode = 'stop';
|
| 666 |
+
if (queuedVisionDownload === queued) queuedVisionDownload = null;
|
| 667 |
+
}
|
| 668 |
+
if (targetsActive) {
|
| 669 |
+
active.cancelMode = 'stop';
|
| 670 |
+
visionDownloadAbortController?.abort();
|
| 671 |
+
}
|
| 672 |
+
return { targetsQueued, targetsActive, hasActiveVision: Boolean(active) };
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
async function getTextRuntime(modelId, dtype, device, { localFilesOnly = false } = {}) {
|
| 676 |
+
assertOnnxTextModel(modelId);
|
| 677 |
+
const key = `text|${modelId}|${device}|${JSON.stringify(dtype)}`;
|
| 678 |
+
if (textRuntime && textRuntimeKey === key) return textRuntime;
|
| 679 |
+
if (textRuntimeLoadPromise) {
|
| 680 |
+
if (textRuntimeLoadKey === key) return textRuntimeLoadPromise;
|
| 681 |
+
await textRuntimeLoadPromise.catch(() => {});
|
| 682 |
+
if (textRuntime && textRuntimeKey === key) return textRuntime;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
const loadPromise = (async () => {
|
| 686 |
+
const library = await loadLibrary();
|
| 687 |
+
if (!library.pipeline) {
|
| 688 |
+
throw new Error('The packaged Transformers.js version does not include text generation.');
|
| 689 |
+
}
|
| 690 |
+
await captureWebGpuAdapterSummary();
|
| 691 |
+
await disposeVisionRuntime('text');
|
| 692 |
+
await disposeTextRuntime();
|
| 693 |
+
const previousAllowLocalModels = library.env?.allowLocalModels;
|
| 694 |
+
if (localFilesOnly && library.env) library.env.allowLocalModels = true;
|
| 695 |
+
let pipeline;
|
| 696 |
+
try {
|
| 697 |
+
pipeline = await library.pipeline('text-generation', modelId, {
|
| 698 |
+
device,
|
| 699 |
+
dtype,
|
| 700 |
+
...(WEBGPU_TEXT_MODEL_FILE_NAMES.has(modelId)
|
| 701 |
+
? { model_file_name: WEBGPU_TEXT_MODEL_FILE_NAMES.get(modelId) }
|
| 702 |
+
: {}),
|
| 703 |
+
// ORT mutates this object while appending its default session config.
|
| 704 |
+
session_options: createWebGpuTextSessionOptions(),
|
| 705 |
+
local_files_only: localFilesOnly,
|
| 706 |
+
progress_callback: event => postProgress(modelId, event),
|
| 707 |
+
});
|
| 708 |
+
} finally {
|
| 709 |
+
if (localFilesOnly && library.env) library.env.allowLocalModels = previousAllowLocalModels;
|
| 710 |
+
}
|
| 711 |
+
bindWebGpuDeviceDiagnostics(library);
|
| 712 |
+
textRuntime = {
|
| 713 |
+
library,
|
| 714 |
+
pipeline,
|
| 715 |
+
model: pipeline.model,
|
| 716 |
+
tokenizer: pipeline.tokenizer,
|
| 717 |
+
};
|
| 718 |
+
textRuntimeKey = key;
|
| 719 |
+
textRuntimeModelKey = textModelKey(modelId, dtype);
|
| 720 |
+
return textRuntime;
|
| 721 |
+
})();
|
| 722 |
+
textRuntimeLoadPromise = loadPromise;
|
| 723 |
+
textRuntimeLoadKey = key;
|
| 724 |
+
try {
|
| 725 |
+
return await loadPromise;
|
| 726 |
+
} finally {
|
| 727 |
+
if (textRuntimeLoadPromise === loadPromise) {
|
| 728 |
+
textRuntimeLoadPromise = null;
|
| 729 |
+
textRuntimeLoadKey = '';
|
| 730 |
+
}
|
| 731 |
+
}
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
async function getDownloadedTextRuntime(modelId, dtype, device, { localFilesOnly = false } = {}) {
|
| 735 |
+
if (isLfm25VlModel(modelId)) {
|
| 736 |
+
return getVisionRuntime(modelId, dtype, device, {
|
| 737 |
+
localFilesOnly,
|
| 738 |
+
owner: 'text',
|
| 739 |
+
readiness: 'text',
|
| 740 |
+
});
|
| 741 |
+
}
|
| 742 |
+
return getTextRuntime(modelId, dtype, device, { localFilesOnly });
|
| 743 |
+
}
|
| 744 |
+
|
| 745 |
+
async function disposeDownloadedTextRuntime(modelId = '') {
|
| 746 |
+
if (!modelId || isLfm25VlModel(modelId)) await disposeVisionRuntime('text');
|
| 747 |
+
if (!modelId || !isLfm25VlModel(modelId)) await disposeTextRuntime();
|
| 748 |
+
}
|
| 749 |
+
|
| 750 |
+
function chatTemplateText(value) {
|
| 751 |
+
if (typeof value === 'string') return value;
|
| 752 |
+
if (Array.isArray(value)) return value.map(chatTemplateText).join('\n');
|
| 753 |
+
if (value && typeof value === 'object') return Object.values(value).map(chatTemplateText).join('\n');
|
| 754 |
+
return '';
|
| 755 |
+
}
|
| 756 |
+
|
| 757 |
+
export function tokenizerSupportsTools(tokenizer) {
|
| 758 |
+
const template = chatTemplateText(tokenizer?.chat_template ?? tokenizer?.chatTemplate);
|
| 759 |
+
return /\btools\b/.test(template);
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
function assertToolCapableTextRuntime(runtime, modelId) {
|
| 763 |
+
if (tokenizerSupportsTools(runtime?.tokenizer)) return;
|
| 764 |
+
throw new Error(`${modelId} is not compatible with WebBrain: custom repositories must provide a chat template that accepts tools.`);
|
| 765 |
+
}
|
| 766 |
+
|
| 767 |
+
async function getTextDownloadStatus(modelId, dtype) {
|
| 768 |
+
const ready = await isTextModelReady(modelId, dtype);
|
| 769 |
+
const sameModel = sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype);
|
| 770 |
+
if (sameModel && ['downloading', 'paused', 'stopping'].includes(textDownloadState.status)) {
|
| 771 |
+
return textDownloadSnapshot();
|
| 772 |
+
}
|
| 773 |
+
if (ready) {
|
| 774 |
+
return {
|
| 775 |
+
status: 'ready',
|
| 776 |
+
ready: true,
|
| 777 |
+
modelId,
|
| 778 |
+
dtype,
|
| 779 |
+
file: sameModel ? textDownloadState.file : '',
|
| 780 |
+
loaded: sameModel ? textDownloadState.loaded : 0,
|
| 781 |
+
total: sameModel ? textDownloadState.total : 0,
|
| 782 |
+
progress: 100,
|
| 783 |
+
error: '',
|
| 784 |
+
};
|
| 785 |
+
}
|
| 786 |
+
if (sameModel && textDownloadState.status === 'error') return textDownloadSnapshot();
|
| 787 |
+
return {
|
| 788 |
+
status: 'not-downloaded',
|
| 789 |
+
ready: false,
|
| 790 |
+
modelId,
|
| 791 |
+
dtype,
|
| 792 |
+
file: '',
|
| 793 |
+
loaded: 0,
|
| 794 |
+
total: 0,
|
| 795 |
+
progress: 0,
|
| 796 |
+
error: '',
|
| 797 |
+
};
|
| 798 |
+
}
|
| 799 |
+
|
| 800 |
+
async function downloadTextModel(payload, { onStarted } = {}) {
|
| 801 |
+
const modelId = assertOnnxTextModel(payload?.modelId);
|
| 802 |
+
const device = payload?.device || 'webgpu';
|
| 803 |
+
const dtype = payload?.dtype || 'q4f16';
|
| 804 |
+
const tracksDifferentTransfer = textDownloadState.modelId
|
| 805 |
+
&& !sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype)
|
| 806 |
+
&& ['downloading', 'paused', 'stopping'].includes(textDownloadState.status);
|
| 807 |
+
if (tracksDifferentTransfer) {
|
| 808 |
+
throw new Error(`Finish or stop the ${textDownloadState.modelId} download before downloading ${modelId}.`);
|
| 809 |
+
}
|
| 810 |
+
await clearLegacyLfm25VlWrongPrecisionCache(modelId);
|
| 811 |
+
if (await isTextModelReady(modelId, dtype)) {
|
| 812 |
+
if (payload?.requireTools === true) {
|
| 813 |
+
const runtime = await getDownloadedTextRuntime(modelId, dtype, device, { localFilesOnly: true });
|
| 814 |
+
assertToolCapableTextRuntime(runtime, modelId);
|
| 815 |
+
}
|
| 816 |
+
textDownloadState = {
|
| 817 |
+
...textDownloadState,
|
| 818 |
+
status: 'ready',
|
| 819 |
+
ready: true,
|
| 820 |
+
modelId,
|
| 821 |
+
dtype,
|
| 822 |
+
progress: 100,
|
| 823 |
+
error: '',
|
| 824 |
+
};
|
| 825 |
+
postTextDownloadState({ force: true });
|
| 826 |
+
return textDownloadSnapshot();
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
const resuming = textDownloadState.status === 'paused'
|
| 830 |
+
&& sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype);
|
| 831 |
+
if (!resuming) textDownloadFiles.clear();
|
| 832 |
+
activeTextDownloadModelId = modelId;
|
| 833 |
+
textDownloadCancelMode = '';
|
| 834 |
+
const controller = new AbortController();
|
| 835 |
+
textDownloadAbortController = controller;
|
| 836 |
+
textDownloadState = {
|
| 837 |
+
status: 'downloading',
|
| 838 |
+
ready: false,
|
| 839 |
+
modelId,
|
| 840 |
+
dtype,
|
| 841 |
+
file: resuming ? textDownloadState.file : '',
|
| 842 |
+
loaded: resuming ? textDownloadState.loaded : 0,
|
| 843 |
+
total: resuming ? textDownloadState.total : 0,
|
| 844 |
+
progress: resuming ? textDownloadState.progress : 0,
|
| 845 |
+
error: '',
|
| 846 |
+
};
|
| 847 |
+
postTextDownloadState({ force: true });
|
| 848 |
+
onStarted?.(textDownloadSnapshot());
|
| 849 |
+
|
| 850 |
+
try {
|
| 851 |
+
const runtime = await getDownloadedTextRuntime(modelId, dtype, device);
|
| 852 |
+
if (payload?.requireTools === true) assertToolCapableTextRuntime(runtime, modelId);
|
| 853 |
+
if (textDownloadCancelMode) {
|
| 854 |
+
await disposeDownloadedTextRuntime(modelId);
|
| 855 |
+
return textDownloadSnapshot();
|
| 856 |
+
}
|
| 857 |
+
await markTextModelReady(modelId, dtype);
|
| 858 |
+
textDownloadState = {
|
| 859 |
+
...textDownloadState,
|
| 860 |
+
status: 'ready',
|
| 861 |
+
ready: true,
|
| 862 |
+
progress: 100,
|
| 863 |
+
error: '',
|
| 864 |
+
};
|
| 865 |
+
postTextDownloadState({ force: true });
|
| 866 |
+
return textDownloadSnapshot();
|
| 867 |
+
} catch (error) {
|
| 868 |
+
if (textDownloadCancelMode === 'pause' || textDownloadCancelMode === 'stop' || controller.signal.aborted) {
|
| 869 |
+
textDownloadState = {
|
| 870 |
+
...textDownloadState,
|
| 871 |
+
status: textDownloadCancelMode === 'stop' ? 'stopping' : 'paused',
|
| 872 |
+
ready: false,
|
| 873 |
+
error: '',
|
| 874 |
+
};
|
| 875 |
+
postTextDownloadState({ force: true });
|
| 876 |
+
return textDownloadSnapshot();
|
| 877 |
+
}
|
| 878 |
+
textDownloadState = {
|
| 879 |
+
...textDownloadState,
|
| 880 |
+
status: 'error',
|
| 881 |
+
ready: false,
|
| 882 |
+
error: error?.message || String(error),
|
| 883 |
+
};
|
| 884 |
+
postTextDownloadState({ force: true });
|
| 885 |
+
throw error;
|
| 886 |
+
} finally {
|
| 887 |
+
if (textDownloadAbortController === controller) textDownloadAbortController = null;
|
| 888 |
+
activeTextDownloadModelId = '';
|
| 889 |
+
}
|
| 890 |
+
}
|
| 891 |
+
|
| 892 |
+
async function clearLegacyLfm25VlWrongPrecisionCache(modelId) {
|
| 893 |
+
if (modelId !== WEBGPU_LFM25_VL_16B_MODEL_ID || typeof caches === 'undefined') return 0;
|
| 894 |
+
const modelPath = `/${modelId}/`;
|
| 895 |
+
const wrongPrecisionFile = /\/onnx\/(?:decoder|embed_images)\.onnx(?:_data(?:_\d+)?)?(?:[?#]|$)/;
|
| 896 |
+
let deletedEntries = 0;
|
| 897 |
+
for (const name of await caches.keys()) {
|
| 898 |
+
if (!/transformers/i.test(name)) continue;
|
| 899 |
+
const cache = await caches.open(name);
|
| 900 |
+
for (const request of await cache.keys()) {
|
| 901 |
+
const url = safeDecodedUrl(request.url);
|
| 902 |
+
if (url.includes(modelPath) && wrongPrecisionFile.test(url) && await cache.delete(request)) {
|
| 903 |
+
deletedEntries++;
|
| 904 |
+
}
|
| 905 |
+
}
|
| 906 |
+
}
|
| 907 |
+
return deletedEntries;
|
| 908 |
+
}
|
| 909 |
+
|
| 910 |
+
function pauseTextDownload() {
|
| 911 |
+
if (textDownloadState.status !== 'downloading') return textDownloadSnapshot();
|
| 912 |
+
textDownloadCancelMode = 'pause';
|
| 913 |
+
textDownloadState = { ...textDownloadState, status: 'paused', ready: false, error: '' };
|
| 914 |
+
textDownloadAbortController?.abort();
|
| 915 |
+
postTextDownloadState({ force: true });
|
| 916 |
+
return textDownloadSnapshot();
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
async function clearTextModelCache(modelId, dtype) {
|
| 920 |
+
if (textRuntimeModelKey === textModelKey(modelId, dtype)) await disposeTextRuntime();
|
| 921 |
+
if (visionRuntimeOwner === 'text' && visionRuntimeModelKey === textModelKey(modelId, dtype)) {
|
| 922 |
+
await disposeVisionRuntime('text');
|
| 923 |
+
}
|
| 924 |
+
const modelPath = `/${modelId}/`;
|
| 925 |
+
const markerUrl = textReadyMarkerUrl(modelId, dtype);
|
| 926 |
+
if (typeof caches !== 'undefined') {
|
| 927 |
+
for (const name of await caches.keys()) {
|
| 928 |
+
if (!/transformers/i.test(name)) continue;
|
| 929 |
+
const cache = await caches.open(name);
|
| 930 |
+
for (const request of await cache.keys()) {
|
| 931 |
+
const url = safeDecodedUrl(request.url);
|
| 932 |
+
if (url.includes(modelPath) || request.url === markerUrl) await cache.delete(request);
|
| 933 |
+
}
|
| 934 |
+
await cache.delete(markerUrl);
|
| 935 |
+
}
|
| 936 |
+
}
|
| 937 |
+
readyTextModelKeys.delete(textModelKey(modelId, dtype));
|
| 938 |
+
textDownloadFiles.clear();
|
| 939 |
+
textDownloadCancelMode = '';
|
| 940 |
+
const clearedState = {
|
| 941 |
+
status: 'not-downloaded',
|
| 942 |
+
ready: false,
|
| 943 |
+
modelId,
|
| 944 |
+
dtype,
|
| 945 |
+
file: '',
|
| 946 |
+
loaded: 0,
|
| 947 |
+
total: 0,
|
| 948 |
+
progress: 0,
|
| 949 |
+
error: '',
|
| 950 |
+
};
|
| 951 |
+
const sameModel = !textDownloadState.modelId
|
| 952 |
+
|| sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype);
|
| 953 |
+
if (sameModel) {
|
| 954 |
+
textDownloadState = clearedState;
|
| 955 |
+
postTextDownloadState({ force: true });
|
| 956 |
+
}
|
| 957 |
+
return { ...clearedState };
|
| 958 |
+
}
|
| 959 |
+
|
| 960 |
+
function enqueueModelOperation(operation) {
|
| 961 |
+
const result = modelOperationQueue.then(operation, operation);
|
| 962 |
+
// Keep the queue usable after one request fails while preserving that
|
| 963 |
+
// failure for the caller awaiting `result`.
|
| 964 |
+
modelOperationQueue = result.catch(() => {});
|
| 965 |
+
return result;
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
+
function imageUrlFromBlock(block) {
|
| 969 |
+
if (block?.type === 'image_url') {
|
| 970 |
+
return typeof block.image_url === 'string'
|
| 971 |
+
? block.image_url
|
| 972 |
+
: block.image_url?.url;
|
| 973 |
+
}
|
| 974 |
+
if (block?.type === 'image') {
|
| 975 |
+
return typeof block.image === 'string' ? block.image : block.url;
|
| 976 |
+
}
|
| 977 |
+
return '';
|
| 978 |
+
}
|
| 979 |
+
|
| 980 |
+
function prepareMultimodalMessages(messages) {
|
| 981 |
+
const imageUrls = [];
|
| 982 |
+
const prepared = [];
|
| 983 |
+
for (const message of Array.isArray(messages) ? messages : []) {
|
| 984 |
+
if (!message || typeof message !== 'object') continue;
|
| 985 |
+
const role = ['system', 'user', 'assistant', 'tool'].includes(message.role)
|
| 986 |
+
? message.role
|
| 987 |
+
: 'user';
|
| 988 |
+
const imageBlocks = [];
|
| 989 |
+
const textBlocks = [];
|
| 990 |
+
if (Array.isArray(message.content)) {
|
| 991 |
+
for (const block of message.content) {
|
| 992 |
+
if (block?.type === 'text' && typeof block.text === 'string') {
|
| 993 |
+
textBlocks.push({ type: 'text', text: block.text });
|
| 994 |
+
continue;
|
| 995 |
+
}
|
| 996 |
+
const imageUrl = imageUrlFromBlock(block);
|
| 997 |
+
if (imageUrl) {
|
| 998 |
+
imageUrls.push(imageUrl);
|
| 999 |
+
imageBlocks.push({ type: 'image' });
|
| 1000 |
+
}
|
| 1001 |
+
}
|
| 1002 |
+
} else if (typeof message.content === 'string') {
|
| 1003 |
+
textBlocks.push({ type: 'text', text: message.content });
|
| 1004 |
+
}
|
| 1005 |
+
// LFM2.5-VL's published chat template places <image> before the question.
|
| 1006 |
+
// Normalize OpenAI-style messages (which often put text first) to that
|
| 1007 |
+
// model-specific contract without changing the provider-facing API.
|
| 1008 |
+
const blocks = [...imageBlocks, ...textBlocks];
|
| 1009 |
+
if (blocks.length || Array.isArray(message.tool_calls)) {
|
| 1010 |
+
prepared.push({
|
| 1011 |
+
role,
|
| 1012 |
+
content: blocks,
|
| 1013 |
+
...(Array.isArray(message.tool_calls)
|
| 1014 |
+
? { tool_calls: message.tool_calls.map(normalizeTextToolCall) }
|
| 1015 |
+
: {}),
|
| 1016 |
+
...(message.reasoning_content ? { reasoning_content: String(message.reasoning_content) } : {}),
|
| 1017 |
+
});
|
| 1018 |
+
}
|
| 1019 |
+
}
|
| 1020 |
+
return { messages: prepared, imageUrls };
|
| 1021 |
+
}
|
| 1022 |
+
|
| 1023 |
+
function createVisionProbeImage(RawImage) {
|
| 1024 |
+
if (!RawImage) throw new Error('The packaged runtime does not expose RawImage.');
|
| 1025 |
+
// LFM2.5-VL-450M is much more dependable at coarse visual classification
|
| 1026 |
+
// than fine OCR. Use three large, unlabeled color panels so the connection
|
| 1027 |
+
// test still proves that pixels reached the model without asking it to read
|
| 1028 |
+
// tiny synthetic glyphs.
|
| 1029 |
+
const width = 480;
|
| 1030 |
+
const height = 320;
|
| 1031 |
+
const channels = 3;
|
| 1032 |
+
const colors = [
|
| 1033 |
+
[255, 255, 0],
|
| 1034 |
+
[0, 0, 255],
|
| 1035 |
+
[255, 0, 0],
|
| 1036 |
+
];
|
| 1037 |
+
const data = new Uint8ClampedArray(width * height * channels);
|
| 1038 |
+
for (let y = 0; y < height; y++) {
|
| 1039 |
+
for (let x = 0; x < width; x++) {
|
| 1040 |
+
const targetOffset = (y * width + x) * channels;
|
| 1041 |
+
const color = colors[Math.min(colors.length - 1, Math.floor(x / (width / colors.length)))];
|
| 1042 |
+
for (let channel = 0; channel < channels; channel++) {
|
| 1043 |
+
data[targetOffset + channel] = color[channel];
|
| 1044 |
+
}
|
| 1045 |
+
}
|
| 1046 |
+
}
|
| 1047 |
+
return new RawImage(data, width, height, channels);
|
| 1048 |
+
}
|
| 1049 |
+
|
| 1050 |
+
async function runVision(payload, requestId) {
|
| 1051 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1052 |
+
if (!modelId) throw new Error('No vision model was specified.');
|
| 1053 |
+
const device = payload?.device || 'webgpu';
|
| 1054 |
+
const dtype = payload?.dtype || {
|
| 1055 |
+
embed_tokens: 'fp16',
|
| 1056 |
+
vision_encoder: 'fp16',
|
| 1057 |
+
decoder_model_merged: 'q4',
|
| 1058 |
+
};
|
| 1059 |
+
const library = await loadLibrary();
|
| 1060 |
+
const stoppingCriteria = library.InterruptableStoppingCriteria
|
| 1061 |
+
? new library.InterruptableStoppingCriteria()
|
| 1062 |
+
: null;
|
| 1063 |
+
if (stoppingCriteria) activeVisionGenerations.set(requestId, stoppingCriteria);
|
| 1064 |
+
try {
|
| 1065 |
+
if (cancelledVisionGenerations.has(requestId)) {
|
| 1066 |
+
const error = new Error('Vision generation was cancelled.');
|
| 1067 |
+
error.name = 'AbortError';
|
| 1068 |
+
throw error;
|
| 1069 |
+
}
|
| 1070 |
+
const runtime = await getVisionRuntime(modelId, dtype, device, {
|
| 1071 |
+
localFilesOnly: true,
|
| 1072 |
+
owner: 'vision',
|
| 1073 |
+
readiness: 'vision',
|
| 1074 |
+
});
|
| 1075 |
+
const { messages, imageUrls } = prepareMultimodalMessages(payload?.messages);
|
| 1076 |
+
if (imageUrls.length !== 1) {
|
| 1077 |
+
throw new Error(`LFM2.5-VL requires exactly one screenshot; received ${imageUrls.length}.`);
|
| 1078 |
+
}
|
| 1079 |
+
const prompt = runtime.processor.apply_chat_template(messages, {
|
| 1080 |
+
add_generation_prompt: true,
|
| 1081 |
+
});
|
| 1082 |
+
const image = payload?.options?.visionProbe === true
|
| 1083 |
+
? createVisionProbeImage(runtime.library.RawImage)
|
| 1084 |
+
: await runtime.library.load_image(imageUrls[0]);
|
| 1085 |
+
const inputs = await runtime.processor(image, prompt, { add_special_tokens: false });
|
| 1086 |
+
const requestedTokens = Number(payload?.options?.maxTokens);
|
| 1087 |
+
const maxNewTokens = Number.isFinite(requestedTokens)
|
| 1088 |
+
? Math.max(1, Math.min(1600, Math.round(requestedTokens)))
|
| 1089 |
+
: 800;
|
| 1090 |
+
const outputs = await runtime.model.generate({
|
| 1091 |
+
...inputs,
|
| 1092 |
+
do_sample: false,
|
| 1093 |
+
max_new_tokens: maxNewTokens,
|
| 1094 |
+
...(stoppingCriteria ? { stopping_criteria: [stoppingCriteria] } : {}),
|
| 1095 |
+
});
|
| 1096 |
+
if (cancelledVisionGenerations.has(requestId)) {
|
| 1097 |
+
const error = new Error('Vision generation was cancelled.');
|
| 1098 |
+
error.name = 'AbortError';
|
| 1099 |
+
throw error;
|
| 1100 |
+
}
|
| 1101 |
+
const inputLength = inputs.input_ids.dims.at(-1);
|
| 1102 |
+
const generated = outputs.slice(null, [inputLength, null]);
|
| 1103 |
+
const decoded = runtime.processor.batch_decode(generated, { skip_special_tokens: true });
|
| 1104 |
+
return String(decoded?.[0] || '').trim();
|
| 1105 |
+
} finally {
|
| 1106 |
+
activeVisionGenerations.delete(requestId);
|
| 1107 |
+
cancelledVisionGenerations.delete(requestId);
|
| 1108 |
+
}
|
| 1109 |
+
}
|
| 1110 |
+
|
| 1111 |
+
function normalizeTextToolCall(toolCall) {
|
| 1112 |
+
if (!toolCall || typeof toolCall !== 'object') return toolCall;
|
| 1113 |
+
const usesFunctionWrapper = toolCall.function && typeof toolCall.function === 'object';
|
| 1114 |
+
const target = usesFunctionWrapper ? toolCall.function : toolCall;
|
| 1115 |
+
let parsedArguments = target.arguments;
|
| 1116 |
+
if (typeof parsedArguments === 'string') {
|
| 1117 |
+
try {
|
| 1118 |
+
parsedArguments = JSON.parse(parsedArguments);
|
| 1119 |
+
} catch {
|
| 1120 |
+
parsedArguments = {};
|
| 1121 |
+
}
|
| 1122 |
+
}
|
| 1123 |
+
if (!parsedArguments || typeof parsedArguments !== 'object' || Array.isArray(parsedArguments)) {
|
| 1124 |
+
// Ling's template calls .items() unconditionally, so malformed or omitted
|
| 1125 |
+
// historical arguments must still be represented by an object.
|
| 1126 |
+
parsedArguments = {};
|
| 1127 |
+
}
|
| 1128 |
+
if (parsedArguments === target.arguments) return toolCall;
|
| 1129 |
+
|
| 1130 |
+
if (usesFunctionWrapper) {
|
| 1131 |
+
return {
|
| 1132 |
+
...toolCall,
|
| 1133 |
+
function: { ...target, arguments: parsedArguments },
|
| 1134 |
+
};
|
| 1135 |
+
}
|
| 1136 |
+
return { ...toolCall, arguments: parsedArguments };
|
| 1137 |
+
}
|
| 1138 |
+
|
| 1139 |
+
export function prepareTextMessages(messages) {
|
| 1140 |
+
return (Array.isArray(messages) ? messages : []).map(message => {
|
| 1141 |
+
if (!message || typeof message !== 'object') return { role: 'user', content: '' };
|
| 1142 |
+
const prepared = {
|
| 1143 |
+
...message,
|
| 1144 |
+
...(Array.isArray(message.tool_calls)
|
| 1145 |
+
? { tool_calls: message.tool_calls.map(normalizeTextToolCall) }
|
| 1146 |
+
: {}),
|
| 1147 |
+
};
|
| 1148 |
+
if (Array.isArray(message.content)) {
|
| 1149 |
+
const text = message.content
|
| 1150 |
+
.filter(block => block?.type === 'text' && typeof block.text === 'string')
|
| 1151 |
+
.map(block => block.text)
|
| 1152 |
+
.join('\n');
|
| 1153 |
+
return { ...prepared, content: text };
|
| 1154 |
+
}
|
| 1155 |
+
return { ...prepared, content: String(message.content || '') };
|
| 1156 |
+
});
|
| 1157 |
+
}
|
| 1158 |
+
|
| 1159 |
+
export function splitThinking(content, { openingTagInPrompt = false } = {}) {
|
| 1160 |
+
const source = String(content || '').trim();
|
| 1161 |
+
const match = /^<think>\s*([\s\S]*?)\s*<\/think>\s*([\s\S]*)$/i.exec(source);
|
| 1162 |
+
if (match) {
|
| 1163 |
+
return {
|
| 1164 |
+
content: String(match[2] || '').trim(),
|
| 1165 |
+
reasoningContent: String(match[1] || '').trim() || null,
|
| 1166 |
+
incompleteReasoning: false,
|
| 1167 |
+
};
|
| 1168 |
+
}
|
| 1169 |
+
if (!openingTagInPrompt) {
|
| 1170 |
+
return { content: source, reasoningContent: null, incompleteReasoning: false };
|
| 1171 |
+
}
|
| 1172 |
+
|
| 1173 |
+
// LFM2.5's official template places `<think>` in the generation prompt.
|
| 1174 |
+
// Transformers.js therefore returns only the generated suffix: reasoning,
|
| 1175 |
+
// `</think>`, then the user-facing answer.
|
| 1176 |
+
const closingTag = /<\/think>/i.exec(source);
|
| 1177 |
+
if (!closingTag) {
|
| 1178 |
+
return {
|
| 1179 |
+
content: '',
|
| 1180 |
+
reasoningContent: source || null,
|
| 1181 |
+
incompleteReasoning: !!source,
|
| 1182 |
+
};
|
| 1183 |
+
}
|
| 1184 |
+
return {
|
| 1185 |
+
content: source.slice(closingTag.index + closingTag[0].length).trim(),
|
| 1186 |
+
reasoningContent: source.slice(0, closingTag.index).trim() || null,
|
| 1187 |
+
incompleteReasoning: false,
|
| 1188 |
+
};
|
| 1189 |
+
}
|
| 1190 |
+
|
| 1191 |
+
function addLegacyVlTools(messages, tools) {
|
| 1192 |
+
if (!tools.length) return messages;
|
| 1193 |
+
const toolText = `List of tools: [${tools.map(tool => JSON.stringify(tool)).join(', ')}]`;
|
| 1194 |
+
const prepared = messages.map(message => ({ ...message, content: [...(message.content || [])] }));
|
| 1195 |
+
if (prepared[0]?.role === 'system') {
|
| 1196 |
+
prepared[0].content.push({ type: 'text', text: `\n${toolText}` });
|
| 1197 |
+
} else {
|
| 1198 |
+
prepared.unshift({ role: 'system', content: [{ type: 'text', text: toolText }] });
|
| 1199 |
+
}
|
| 1200 |
+
return prepared;
|
| 1201 |
+
}
|
| 1202 |
+
|
| 1203 |
+
async function runMultimodalText(payload) {
|
| 1204 |
+
const modelId = assertOnnxTextModel(payload?.modelId);
|
| 1205 |
+
if (!isLfm25VlModel(modelId)) {
|
| 1206 |
+
throw new Error(`${modelId} is not a shipped WebGPU multimodal model.`);
|
| 1207 |
+
}
|
| 1208 |
+
const device = payload?.device || 'webgpu';
|
| 1209 |
+
const dtype = payload?.dtype || {
|
| 1210 |
+
embed_tokens: 'fp16',
|
| 1211 |
+
vision_encoder: 'fp16',
|
| 1212 |
+
decoder_model_merged: 'q4',
|
| 1213 |
+
};
|
| 1214 |
+
if (!await isTextModelReady(modelId, dtype)) {
|
| 1215 |
+
throw new Error(`${modelId} is not downloaded. Open Apocalypse Mode > WebGPU to download it before chatting.`);
|
| 1216 |
+
}
|
| 1217 |
+
const runtime = await getVisionRuntime(modelId, dtype, device, {
|
| 1218 |
+
localFilesOnly: true,
|
| 1219 |
+
owner: 'text',
|
| 1220 |
+
readiness: 'text',
|
| 1221 |
+
});
|
| 1222 |
+
const tools = Array.isArray(payload?.options?.tools) ? payload.options.tools : [];
|
| 1223 |
+
let { messages, imageUrls } = prepareMultimodalMessages(payload?.messages);
|
| 1224 |
+
if (modelId === WEBGPU_LFM25_VL_16B_MODEL_ID) messages = addLegacyVlTools(messages, tools);
|
| 1225 |
+
const prompt = runtime.processor.apply_chat_template(messages, {
|
| 1226 |
+
add_generation_prompt: true,
|
| 1227 |
+
tools: tools.length ? tools : undefined,
|
| 1228 |
+
});
|
| 1229 |
+
let inputs;
|
| 1230 |
+
if (imageUrls.length) {
|
| 1231 |
+
const images = await Promise.all(imageUrls.map(url => runtime.library.load_image(url)));
|
| 1232 |
+
inputs = await runtime.processor(images.length === 1 ? images[0] : images, prompt, {
|
| 1233 |
+
add_special_tokens: false,
|
| 1234 |
+
});
|
| 1235 |
+
} else {
|
| 1236 |
+
inputs = runtime.processor.tokenizer(prompt, { add_special_tokens: false });
|
| 1237 |
+
}
|
| 1238 |
+
const requestedTokens = Number(payload?.options?.maxTokens);
|
| 1239 |
+
const maxNewTokens = Number.isFinite(requestedTokens)
|
| 1240 |
+
? Math.max(1, Math.min(1600, Math.round(requestedTokens)))
|
| 1241 |
+
: 800;
|
| 1242 |
+
lastWebGpuDeviceError = '';
|
| 1243 |
+
lastWebGpuDeviceLost = '';
|
| 1244 |
+
let outputs;
|
| 1245 |
+
try {
|
| 1246 |
+
outputs = await runtime.model.generate({
|
| 1247 |
+
...inputs,
|
| 1248 |
+
do_sample: false,
|
| 1249 |
+
max_new_tokens: maxNewTokens,
|
| 1250 |
+
});
|
| 1251 |
+
} catch (error) {
|
| 1252 |
+
if (isWebGpuExecutionFailure(error)) throw await enrichWebGpuExecutionError(error);
|
| 1253 |
+
throw error;
|
| 1254 |
+
}
|
| 1255 |
+
const inputLength = inputs.input_ids.dims.at(-1);
|
| 1256 |
+
const generated = outputs.slice(null, [inputLength, null]);
|
| 1257 |
+
const decoded = runtime.processor.batch_decode(generated, { skip_special_tokens: true });
|
| 1258 |
+
const result = splitThinking(String(decoded?.[0] || '').trim());
|
| 1259 |
+
return { content: result.content, reasoningContent: result.reasoningContent };
|
| 1260 |
+
}
|
| 1261 |
+
|
| 1262 |
+
async function runText(payload) {
|
| 1263 |
+
const modelId = assertOnnxTextModel(payload?.modelId);
|
| 1264 |
+
const device = payload?.device || 'webgpu';
|
| 1265 |
+
const dtype = payload?.dtype || 'q4f16';
|
| 1266 |
+
const usesReasoningTemplate = WEBGPU_REASONING_MODEL_IDS.has(modelId);
|
| 1267 |
+
const opensThinkingInPrompt = WEBGPU_OPEN_THINKING_MODEL_IDS.has(modelId);
|
| 1268 |
+
const usesLongOutputBudget = WEBGPU_LONG_OUTPUT_MODEL_IDS.has(modelId);
|
| 1269 |
+
const sampling = WEBGPU_TEXT_SAMPLING.get(modelId);
|
| 1270 |
+
if (!await isTextModelReady(modelId, dtype)) {
|
| 1271 |
+
throw new Error(`${modelId} is not downloaded. Open Apocalypse Mode > WebGPU to download it before chatting.`);
|
| 1272 |
+
}
|
| 1273 |
+
const runtime = await getTextRuntime(modelId, dtype, device, { localFilesOnly: true });
|
| 1274 |
+
if (payload?.requireTools === true) assertToolCapableTextRuntime(runtime, modelId);
|
| 1275 |
+
const requestedTokens = Number(payload?.options?.maxTokens);
|
| 1276 |
+
const maxTokenLimit = usesLongOutputBudget
|
| 1277 |
+
? WEBGPU_LFM25_MAX_NEW_TOKENS
|
| 1278 |
+
: WEBGPU_TEXT_MAX_NEW_TOKENS;
|
| 1279 |
+
const maxNewTokens = Number.isFinite(requestedTokens)
|
| 1280 |
+
? Math.max(1, Math.min(maxTokenLimit, Math.round(requestedTokens)))
|
| 1281 |
+
: maxTokenLimit;
|
| 1282 |
+
const tools = Array.isArray(payload?.options?.tools) ? payload.options.tools : [];
|
| 1283 |
+
lastWebGpuDeviceError = '';
|
| 1284 |
+
lastWebGpuDeviceLost = '';
|
| 1285 |
+
let output;
|
| 1286 |
+
try {
|
| 1287 |
+
output = await runtime.pipeline(prepareTextMessages(payload?.messages), {
|
| 1288 |
+
do_sample: Boolean(sampling),
|
| 1289 |
+
...(sampling || {}),
|
| 1290 |
+
max_new_tokens: maxNewTokens,
|
| 1291 |
+
tools: tools.length ? tools : undefined,
|
| 1292 |
+
// Reasoning templates re-open `<think>` for the pending turn and collapse
|
| 1293 |
+
// completed thinking in history; the rest suppress thinking outright.
|
| 1294 |
+
tokenizer_encode_kwargs: usesReasoningTemplate
|
| 1295 |
+
? { preserve_thinking: false }
|
| 1296 |
+
: { enable_thinking: false },
|
| 1297 |
+
});
|
| 1298 |
+
} catch (error) {
|
| 1299 |
+
if (isWebGpuExecutionFailure(error)) throw await enrichWebGpuExecutionError(error);
|
| 1300 |
+
throw error;
|
| 1301 |
+
}
|
| 1302 |
+
const generated = output?.[0]?.generated_text;
|
| 1303 |
+
const content = Array.isArray(generated)
|
| 1304 |
+
? generated.at(-1)?.content
|
| 1305 |
+
: generated;
|
| 1306 |
+
if (typeof content !== 'string') {
|
| 1307 |
+
throw new Error('The WebGPU model returned no generated text.');
|
| 1308 |
+
}
|
| 1309 |
+
const result = splitThinking(content, { openingTagInPrompt: opensThinkingInPrompt });
|
| 1310 |
+
if (result.incompleteReasoning) {
|
| 1311 |
+
throw new Error(`${modelId} used its generation budget before finishing reasoning. Retry with a shorter prompt.`);
|
| 1312 |
+
}
|
| 1313 |
+
return { content: result.content, reasoningContent: result.reasoningContent };
|
| 1314 |
+
}
|
| 1315 |
+
|
| 1316 |
+
async function probeRuntime() {
|
| 1317 |
+
await loadLibrary();
|
| 1318 |
+
const hasWebGPU = typeof navigator !== 'undefined' && !!navigator.gpu;
|
| 1319 |
+
let adapter = null;
|
| 1320 |
+
if (hasWebGPU) {
|
| 1321 |
+
try { adapter = await navigator.gpu.requestAdapter({ powerPreference: 'high-performance' }); } catch {}
|
| 1322 |
+
}
|
| 1323 |
+
const isFallbackAdapter = !!(adapter?.isFallbackAdapter ?? adapter?.info?.isFallbackAdapter);
|
| 1324 |
+
return {
|
| 1325 |
+
libraryVersion,
|
| 1326 |
+
hasWebGPU: hasWebGPU && !!adapter,
|
| 1327 |
+
isFallbackAdapter,
|
| 1328 |
+
adapterFeatures: adapter ? [...adapter.features].slice(0, 12) : [],
|
| 1329 |
+
};
|
| 1330 |
+
}
|
| 1331 |
+
|
| 1332 |
+
export async function clearVisionModelCache(modelId) {
|
| 1333 |
+
const normalizedModelId = String(modelId || '').trim();
|
| 1334 |
+
if (!normalizedModelId) throw new Error('No vision model was specified.');
|
| 1335 |
+
await disposeVisionRuntime('vision');
|
| 1336 |
+
const modelPath = `/${normalizedModelId}/`;
|
| 1337 |
+
const markerUrl = visionReadyMarkerUrl(normalizedModelId);
|
| 1338 |
+
let deletedEntries = 0;
|
| 1339 |
+
if (typeof caches !== 'undefined') {
|
| 1340 |
+
for (const name of await caches.keys()) {
|
| 1341 |
+
if (!/transformers/i.test(name)) continue;
|
| 1342 |
+
const cache = await caches.open(name);
|
| 1343 |
+
for (const request of await cache.keys()) {
|
| 1344 |
+
const url = safeDecodedUrl(request.url);
|
| 1345 |
+
if (url.includes(modelPath) || isVisionReadyMarkerForModel(request.url, normalizedModelId)) {
|
| 1346 |
+
if (await cache.delete(request)) deletedEntries++;
|
| 1347 |
+
}
|
| 1348 |
+
}
|
| 1349 |
+
if (await cache.delete(markerUrl)) deletedEntries++;
|
| 1350 |
+
}
|
| 1351 |
+
}
|
| 1352 |
+
return { modelId: normalizedModelId, deletedEntries };
|
| 1353 |
+
}
|
| 1354 |
+
|
| 1355 |
+
self.addEventListener('message', async event => {
|
| 1356 |
+
const { id, type, payload } = event.data || {};
|
| 1357 |
+
try {
|
| 1358 |
+
if (type === 'cancel') {
|
| 1359 |
+
const requestId = Number(payload?.requestId);
|
| 1360 |
+
const queued = queuedVisionGenerations.has(requestId);
|
| 1361 |
+
const active = activeVisionGenerations.has(requestId);
|
| 1362 |
+
const cancellable = Number.isFinite(requestId) && (queued || active);
|
| 1363 |
+
if (cancellable) {
|
| 1364 |
+
cancelledVisionGenerations.add(requestId);
|
| 1365 |
+
activeVisionGenerations.get(requestId)?.interrupt?.();
|
| 1366 |
+
}
|
| 1367 |
+
self.postMessage({
|
| 1368 |
+
id,
|
| 1369 |
+
ok: true,
|
| 1370 |
+
cancelled: cancellable,
|
| 1371 |
+
requestId,
|
| 1372 |
+
queued: queued && !active,
|
| 1373 |
+
active,
|
| 1374 |
+
});
|
| 1375 |
+
return;
|
| 1376 |
+
}
|
| 1377 |
+
if (type === 'init') {
|
| 1378 |
+
workerConfig = payload;
|
| 1379 |
+
self.postMessage({ id, ok: true });
|
| 1380 |
+
return;
|
| 1381 |
+
}
|
| 1382 |
+
if (type === 'probe') {
|
| 1383 |
+
self.postMessage({ id, ok: true, ...(await probeRuntime()) });
|
| 1384 |
+
return;
|
| 1385 |
+
}
|
| 1386 |
+
if (type === 'text-download-status') {
|
| 1387 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1388 |
+
const dtype = payload?.dtype || 'q4f16';
|
| 1389 |
+
self.postMessage({ id, ok: true, ...(await getTextDownloadStatus(modelId, dtype)) });
|
| 1390 |
+
return;
|
| 1391 |
+
}
|
| 1392 |
+
if (type === 'download-text') {
|
| 1393 |
+
const state = await enqueueModelOperation(() => downloadTextModel(payload));
|
| 1394 |
+
self.postMessage({ id, ok: true, ...state });
|
| 1395 |
+
return;
|
| 1396 |
+
}
|
| 1397 |
+
if (type === 'start-download-text') {
|
| 1398 |
+
const request = assertTextDownloadCanStart(payload);
|
| 1399 |
+
queuedTextDownload = request;
|
| 1400 |
+
let acknowledged = false;
|
| 1401 |
+
const operation = enqueueModelOperation(() => {
|
| 1402 |
+
if (queuedTextDownload !== request) return getTextDownloadStatus(request.modelId, request.dtype);
|
| 1403 |
+
return downloadTextModel(payload, {
|
| 1404 |
+
onStarted(state) {
|
| 1405 |
+
acknowledged = true;
|
| 1406 |
+
self.postMessage({ id, ok: true, ...state });
|
| 1407 |
+
},
|
| 1408 |
+
});
|
| 1409 |
+
});
|
| 1410 |
+
void operation.then((state) => {
|
| 1411 |
+
if (!acknowledged) self.postMessage({ id, ok: true, ...state });
|
| 1412 |
+
}).catch((error) => {
|
| 1413 |
+
if (!acknowledged) self.postMessage({ id, ok: false, error: error?.message || String(error) });
|
| 1414 |
+
}).finally(() => {
|
| 1415 |
+
if (queuedTextDownload?.key === request.key) queuedTextDownload = null;
|
| 1416 |
+
});
|
| 1417 |
+
return;
|
| 1418 |
+
}
|
| 1419 |
+
if (type === 'pause-text-download') {
|
| 1420 |
+
self.postMessage({ id, ok: true, ...pauseTextDownload() });
|
| 1421 |
+
return;
|
| 1422 |
+
}
|
| 1423 |
+
if (type === 'stop-text-download') {
|
| 1424 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1425 |
+
const dtype = payload?.dtype || 'q4f16';
|
| 1426 |
+
const targetsQueuedTransfer = queuedTextDownload
|
| 1427 |
+
&& sameTextModel(queuedTextDownload.modelId, queuedTextDownload.dtype, modelId, dtype);
|
| 1428 |
+
if (targetsQueuedTransfer) queuedTextDownload = null;
|
| 1429 |
+
const targetsTrackedTransfer = sameTextModel(textDownloadState.modelId, textDownloadState.dtype, modelId, dtype);
|
| 1430 |
+
if (targetsTrackedTransfer) {
|
| 1431 |
+
textDownloadCancelMode = 'stop';
|
| 1432 |
+
textDownloadState = { ...textDownloadState, status: 'stopping', ready: false, error: '' };
|
| 1433 |
+
if (activeTextDownloadModelId === modelId) textDownloadAbortController?.abort();
|
| 1434 |
+
postTextDownloadState({ force: true });
|
| 1435 |
+
}
|
| 1436 |
+
const state = await enqueueModelOperation(() => clearTextModelCache(modelId, dtype));
|
| 1437 |
+
self.postMessage({ id, ok: true, ...state });
|
| 1438 |
+
return;
|
| 1439 |
+
}
|
| 1440 |
+
if (type === 'pause-vision-download') {
|
| 1441 |
+
self.postMessage({ id, ok: true, ...pauseVisionDownload(payload?.modelId) });
|
| 1442 |
+
return;
|
| 1443 |
+
}
|
| 1444 |
+
if (type === 'stop-vision-download') {
|
| 1445 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1446 |
+
if (!modelId) throw new Error('No vision model was specified.');
|
| 1447 |
+
const stopped = stopVisionDownload(modelId);
|
| 1448 |
+
// A queued preload owns no live vision operation. Clear its model-specific
|
| 1449 |
+
// cache immediately so Stop is not trapped behind an unrelated text-model
|
| 1450 |
+
// transfer in the shared WebGPU operation queue. The host may also pass
|
| 1451 |
+
// targetsQueued after pause already dequeued that preload.
|
| 1452 |
+
const targetsQueued = stopped.targetsQueued || payload?.targetsQueued === true;
|
| 1453 |
+
const result = targetsQueued && !stopped.hasActiveVision
|
| 1454 |
+
? await clearVisionModelCache(modelId)
|
| 1455 |
+
: await enqueueModelOperation(() => clearVisionModelCache(modelId));
|
| 1456 |
+
self.postMessage({
|
| 1457 |
+
id,
|
| 1458 |
+
ok: true,
|
| 1459 |
+
status: 'not-downloaded',
|
| 1460 |
+
ready: false,
|
| 1461 |
+
...result,
|
| 1462 |
+
});
|
| 1463 |
+
return;
|
| 1464 |
+
}
|
| 1465 |
+
if (type === 'clear-cache') {
|
| 1466 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1467 |
+
const result = await enqueueModelOperation(() => clearVisionModelCache(modelId));
|
| 1468 |
+
self.postMessage({ id, ok: true, ...result });
|
| 1469 |
+
return;
|
| 1470 |
+
}
|
| 1471 |
+
if (type === 'dispose' || type === 'dispose-all') {
|
| 1472 |
+
await enqueueModelOperation(disposeAllRuntimes);
|
| 1473 |
+
self.postMessage({ id, ok: true, disposed: true });
|
| 1474 |
+
return;
|
| 1475 |
+
}
|
| 1476 |
+
if (type === 'dispose-vision') {
|
| 1477 |
+
await enqueueModelOperation(() => disposeVisionRuntime('vision'));
|
| 1478 |
+
self.postMessage({ id, ok: true, disposed: true });
|
| 1479 |
+
return;
|
| 1480 |
+
}
|
| 1481 |
+
if (type === 'dispose-text') {
|
| 1482 |
+
await enqueueModelOperation(() => disposeDownloadedTextRuntime());
|
| 1483 |
+
self.postMessage({ id, ok: true, disposed: true });
|
| 1484 |
+
return;
|
| 1485 |
+
}
|
| 1486 |
+
if (type === 'preload') {
|
| 1487 |
+
const modelId = String(payload?.modelId || '').trim();
|
| 1488 |
+
if (!modelId) throw new Error('No vision model was specified.');
|
| 1489 |
+
const request = {
|
| 1490 |
+
modelId,
|
| 1491 |
+
dtype: payload?.dtype || '',
|
| 1492 |
+
cancelMode: '',
|
| 1493 |
+
};
|
| 1494 |
+
queuedVisionDownload = request;
|
| 1495 |
+
self.postMessage({ type: 'vision-preload-state', modelId, status: 'queued' });
|
| 1496 |
+
const state = await enqueueModelOperation(() => {
|
| 1497 |
+
self.postMessage({ type: 'vision-preload-state', modelId, status: 'loading' });
|
| 1498 |
+
return preloadVisionModel(payload, request);
|
| 1499 |
+
});
|
| 1500 |
+
if (queuedVisionDownload === request) queuedVisionDownload = null;
|
| 1501 |
+
self.postMessage({ id, ok: true, ...state });
|
| 1502 |
+
return;
|
| 1503 |
+
}
|
| 1504 |
+
if (type === 'chat') {
|
| 1505 |
+
queuedVisionGenerations.add(id);
|
| 1506 |
+
try {
|
| 1507 |
+
const content = await enqueueModelOperation(() => runVision(payload, id));
|
| 1508 |
+
self.postMessage({ id, ok: true, content, raw: { model: payload?.modelId || '' } });
|
| 1509 |
+
} finally {
|
| 1510 |
+
queuedVisionGenerations.delete(id);
|
| 1511 |
+
cancelledVisionGenerations.delete(id);
|
| 1512 |
+
}
|
| 1513 |
+
return;
|
| 1514 |
+
}
|
| 1515 |
+
if (type === 'text-chat') {
|
| 1516 |
+
const result = await enqueueModelOperation(() => runText(payload));
|
| 1517 |
+
self.postMessage({
|
| 1518 |
+
id,
|
| 1519 |
+
ok: true,
|
| 1520 |
+
...result,
|
| 1521 |
+
raw: { model: payload?.modelId || '' },
|
| 1522 |
+
});
|
| 1523 |
+
return;
|
| 1524 |
+
}
|
| 1525 |
+
if (type === 'multimodal-text-chat') {
|
| 1526 |
+
const result = await enqueueModelOperation(() => runMultimodalText(payload));
|
| 1527 |
+
self.postMessage({
|
| 1528 |
+
id,
|
| 1529 |
+
ok: true,
|
| 1530 |
+
...result,
|
| 1531 |
+
raw: { model: payload?.modelId || '' },
|
| 1532 |
+
});
|
| 1533 |
+
return;
|
| 1534 |
+
}
|
| 1535 |
+
throw new Error(`Unknown WebGPU worker message: ${type || 'missing type'}`);
|
| 1536 |
+
} catch (error) {
|
| 1537 |
+
self.postMessage({ id, ok: false, error: error?.message || String(error) });
|
| 1538 |
+
}
|
| 1539 |
+
});
|
runtime/tool-call-parser.js
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Browser-free fallback parser for local models that emit tool calls as text
|
| 2 |
+
// instead of using the provider's structured tool_calls field. This file is
|
| 3 |
+
// mirrored in the Firefox tree; keep both copies byte-identical.
|
| 4 |
+
|
| 5 |
+
// A `{` that never closes must not swallow the rest of the text: models put
|
| 6 |
+
// prose braces, template placeholders, and code snippets around a bare tool
|
| 7 |
+
// call, and the call after them still has to be recovered. Each unbalanced
|
| 8 |
+
// opener costs one extra scan, so the restarts are capped — real text needs
|
| 9 |
+
// none, and the cap keeps a pathological "{{{{…" response from going
|
| 10 |
+
// quadratic over the 10,000-character budget.
|
| 11 |
+
const MAX_UNBALANCED_RESTARTS = 16;
|
| 12 |
+
|
| 13 |
+
/**
|
| 14 |
+
* Collect top-level balanced `{…}` spans, respecting quoted strings and
|
| 15 |
+
* escapes so braces inside JSON string values do not end an object early.
|
| 16 |
+
* Returns offsets rather than substrings so callers can judge each span by
|
| 17 |
+
* where it sits in the surrounding text.
|
| 18 |
+
*/
|
| 19 |
+
function extractBalancedJsonSpans(text) {
|
| 20 |
+
const spans = [];
|
| 21 |
+
let searchFrom = 0;
|
| 22 |
+
let restarts = 0;
|
| 23 |
+
|
| 24 |
+
while (searchFrom < text.length) {
|
| 25 |
+
const start = text.indexOf('{', searchFrom);
|
| 26 |
+
if (start < 0) break;
|
| 27 |
+
let depth = 0;
|
| 28 |
+
let inString = false;
|
| 29 |
+
let escaped = false;
|
| 30 |
+
let end = -1;
|
| 31 |
+
|
| 32 |
+
for (let i = start; i < text.length; i++) {
|
| 33 |
+
const char = text[i];
|
| 34 |
+
if (inString) {
|
| 35 |
+
if (escaped) escaped = false;
|
| 36 |
+
else if (char === '\\') escaped = true;
|
| 37 |
+
else if (char === '"') inString = false;
|
| 38 |
+
continue;
|
| 39 |
+
}
|
| 40 |
+
if (char === '"') inString = true;
|
| 41 |
+
else if (char === '{') depth++;
|
| 42 |
+
else if (char === '}') {
|
| 43 |
+
depth--;
|
| 44 |
+
if (depth === 0) {
|
| 45 |
+
end = i;
|
| 46 |
+
break;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
if (end < 0) {
|
| 52 |
+
if (++restarts > MAX_UNBALANCED_RESTARTS) break;
|
| 53 |
+
searchFrom = start + 1;
|
| 54 |
+
continue;
|
| 55 |
+
}
|
| 56 |
+
spans.push({ start, end });
|
| 57 |
+
searchFrom = end + 1;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
return spans;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/**
|
| 64 |
+
* True when a span is the whole of its line, ignoring surrounding whitespace
|
| 65 |
+
* and a single trailing comma (models sometimes emit calls as array elements).
|
| 66 |
+
*
|
| 67 |
+
* A model that is CALLING a tool emits the JSON on its own line. A model
|
| 68 |
+
* TALKING ABOUT a call embeds it in a sentence — "I could click with {…} but
|
| 69 |
+
* that is destructive", "The page told me to run {…}, which I ignored",
|
| 70 |
+
* "Option A: {…}". Executing those is wrong in a way that is easy to miss,
|
| 71 |
+
* because a parsed call replaces the model's prose outright: the caller sets
|
| 72 |
+
* `result.content = null`, so the sentence explaining the refusal is dropped
|
| 73 |
+
* and only the refused action survives.
|
| 74 |
+
*
|
| 75 |
+
* The trade-off is that a genuine call written mid-sentence is not recovered.
|
| 76 |
+
* That is the safer side to err on here: this fallback exists for models that
|
| 77 |
+
* emit a call INSTEAD of prose, and those put it on its own line.
|
| 78 |
+
*/
|
| 79 |
+
function standsAloneOnLine(text, start, end) {
|
| 80 |
+
const before = text.slice(0, start);
|
| 81 |
+
const lineHead = before.slice(before.lastIndexOf('\n') + 1).trim();
|
| 82 |
+
if (lineHead !== '') return false;
|
| 83 |
+
|
| 84 |
+
const after = text.slice(end + 1);
|
| 85 |
+
const newline = after.indexOf('\n');
|
| 86 |
+
const lineTail = (newline < 0 ? after : after.slice(0, newline)).trim();
|
| 87 |
+
return lineTail === '' || lineTail === ',';
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/**
|
| 91 |
+
* Parse a batch only when the entire trimmed response is a JSON array. Every
|
| 92 |
+
* element must itself be an allowed call; otherwise reject the batch rather
|
| 93 |
+
* than executing an allowed-looking subset of mixed or narrated content.
|
| 94 |
+
*
|
| 95 |
+
* `null` means the response was not a valid whole-response array and the
|
| 96 |
+
* existing fallbacks may continue. An empty array means it was an array but
|
| 97 |
+
* was empty or unsafe, so callers must not scan inside it for partial calls.
|
| 98 |
+
*/
|
| 99 |
+
function parseWholeResponseJsonArray(text, allowedNames) {
|
| 100 |
+
const trimmed = text.trim();
|
| 101 |
+
if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return null;
|
| 102 |
+
|
| 103 |
+
let parsed;
|
| 104 |
+
try {
|
| 105 |
+
parsed = JSON.parse(trimmed);
|
| 106 |
+
} catch {
|
| 107 |
+
return null;
|
| 108 |
+
}
|
| 109 |
+
if (!Array.isArray(parsed)) return null;
|
| 110 |
+
if (!parsed.every(obj => (
|
| 111 |
+
obj
|
| 112 |
+
&& typeof obj === 'object'
|
| 113 |
+
&& !Array.isArray(obj)
|
| 114 |
+
&& typeof obj.name === 'string'
|
| 115 |
+
&& allowedNames.has(obj.name)
|
| 116 |
+
))) return [];
|
| 117 |
+
return parsed;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
/**
|
| 121 |
+
* Split on a delimiter only when it is outside strings and nested containers.
|
| 122 |
+
* LFM2.5 emits Python-style calls, but argument arrays and objects are JSON.
|
| 123 |
+
*/
|
| 124 |
+
function splitLfmTopLevel(source, delimiter) {
|
| 125 |
+
const parts = [];
|
| 126 |
+
const closing = { '(': ')', '[': ']', '{': '}' };
|
| 127 |
+
const stack = [];
|
| 128 |
+
let quote = '';
|
| 129 |
+
let escaped = false;
|
| 130 |
+
let start = 0;
|
| 131 |
+
|
| 132 |
+
for (let i = 0; i < source.length; i++) {
|
| 133 |
+
const char = source[i];
|
| 134 |
+
if (quote) {
|
| 135 |
+
if (escaped) escaped = false;
|
| 136 |
+
else if (char === '\\') escaped = true;
|
| 137 |
+
else if (char === quote) quote = '';
|
| 138 |
+
continue;
|
| 139 |
+
}
|
| 140 |
+
if (char === '"' || char === "'") {
|
| 141 |
+
quote = char;
|
| 142 |
+
continue;
|
| 143 |
+
}
|
| 144 |
+
if (closing[char]) {
|
| 145 |
+
stack.push(closing[char]);
|
| 146 |
+
continue;
|
| 147 |
+
}
|
| 148 |
+
if (char === ')' || char === ']' || char === '}') {
|
| 149 |
+
if (stack.pop() !== char) return null;
|
| 150 |
+
continue;
|
| 151 |
+
}
|
| 152 |
+
if (char === delimiter && stack.length === 0) {
|
| 153 |
+
parts.push(source.slice(start, i));
|
| 154 |
+
start = i + 1;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
if (quote || escaped || stack.length > 0) return null;
|
| 159 |
+
parts.push(source.slice(start));
|
| 160 |
+
return parts;
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
function parseLfmString(source) {
|
| 164 |
+
const quote = source[0];
|
| 165 |
+
if ((quote !== '"' && quote !== "'") || source.at(-1) !== quote) return null;
|
| 166 |
+
let output = '';
|
| 167 |
+
const escapes = {
|
| 168 |
+
'\\': '\\',
|
| 169 |
+
'"': '"',
|
| 170 |
+
"'": "'",
|
| 171 |
+
n: '\n',
|
| 172 |
+
r: '\r',
|
| 173 |
+
t: '\t',
|
| 174 |
+
b: '\b',
|
| 175 |
+
f: '\f',
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
for (let i = 1; i < source.length - 1; i++) {
|
| 179 |
+
const char = source[i];
|
| 180 |
+
if (char === quote) return null;
|
| 181 |
+
if (char !== '\\') {
|
| 182 |
+
if (char === '\n' || char === '\r') return null;
|
| 183 |
+
output += char;
|
| 184 |
+
continue;
|
| 185 |
+
}
|
| 186 |
+
if (++i >= source.length - 1) return null;
|
| 187 |
+
const escaped = source[i];
|
| 188 |
+
if (Object.hasOwn(escapes, escaped)) {
|
| 189 |
+
output += escapes[escaped];
|
| 190 |
+
continue;
|
| 191 |
+
}
|
| 192 |
+
const width = escaped === 'u' ? 4 : escaped === 'x' ? 2 : 0;
|
| 193 |
+
const hex = width ? source.slice(i + 1, i + 1 + width) : '';
|
| 194 |
+
if (!width || !new RegExp(`^[0-9a-fA-F]{${width}}$`).test(hex)) return null;
|
| 195 |
+
output += String.fromCodePoint(Number.parseInt(hex, 16));
|
| 196 |
+
i += width;
|
| 197 |
+
}
|
| 198 |
+
return output;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
function parseLfmValue(source) {
|
| 202 |
+
const value = source.trim();
|
| 203 |
+
if (!value) return { ok: false };
|
| 204 |
+
if (value[0] === '"' || value[0] === "'") {
|
| 205 |
+
const parsed = parseLfmString(value);
|
| 206 |
+
return parsed === null ? { ok: false } : { ok: true, value: parsed };
|
| 207 |
+
}
|
| 208 |
+
if (value[0] === '[' || value[0] === '{') {
|
| 209 |
+
try {
|
| 210 |
+
return { ok: true, value: JSON.parse(value) };
|
| 211 |
+
} catch {
|
| 212 |
+
return { ok: false };
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
if (value === 'True' || value === 'true') return { ok: true, value: true };
|
| 216 |
+
if (value === 'False' || value === 'false') return { ok: true, value: false };
|
| 217 |
+
if (value === 'None' || value === 'null') return { ok: true, value: null };
|
| 218 |
+
if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value)) {
|
| 219 |
+
const number = Number(value);
|
| 220 |
+
return Number.isFinite(number) ? { ok: true, value: number } : { ok: false };
|
| 221 |
+
}
|
| 222 |
+
return { ok: false };
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
const LFM_DIRECTIONAL_SCROLL_ALIASES = Object.freeze({
|
| 226 |
+
scrollup: 'up',
|
| 227 |
+
scrolldown: 'down',
|
| 228 |
+
scrolltop: 'top',
|
| 229 |
+
scrollbottom: 'bottom',
|
| 230 |
+
});
|
| 231 |
+
|
| 232 |
+
/**
|
| 233 |
+
* Parse LFM2/LFM2.5's documented native format:
|
| 234 |
+
* <|tool_call_start|>[tool_name(key='value', flag=False)]<|tool_call_end|>
|
| 235 |
+
*
|
| 236 |
+
* The wrapper must occupy the whole response, and every call must be valid and
|
| 237 |
+
* allowlisted. A recognized but unsafe block returns an empty atomic batch so
|
| 238 |
+
* later generic scanners cannot execute JSON fragments embedded inside it.
|
| 239 |
+
*/
|
| 240 |
+
function parseLfmToolCalls(text, allowedNames) {
|
| 241 |
+
const startToken = '<|tool_call_start|>';
|
| 242 |
+
const endToken = '<|tool_call_end|>';
|
| 243 |
+
const source = text.trim();
|
| 244 |
+
if (!source.includes(startToken) && !source.includes(endToken)) return null;
|
| 245 |
+
if (!source.startsWith(startToken) || !source.endsWith(endToken)) return [];
|
| 246 |
+
const inner = source.slice(startToken.length, -endToken.length).trim();
|
| 247 |
+
if (inner.includes(startToken) || inner.includes(endToken)) return [];
|
| 248 |
+
if (!inner.startsWith('[') || !inner.endsWith(']')) return [];
|
| 249 |
+
|
| 250 |
+
const callParts = splitLfmTopLevel(inner.slice(1, -1), ',');
|
| 251 |
+
if (!callParts || callParts.length === 0 || callParts.some(part => !part.trim())) return [];
|
| 252 |
+
const calls = [];
|
| 253 |
+
for (const part of callParts) {
|
| 254 |
+
const match = /^([A-Za-z_]\w*)\s*\(([\s\S]*)\)$/.exec(part.trim());
|
| 255 |
+
if (!match) return [];
|
| 256 |
+
const aliasDirection = LFM_DIRECTIONAL_SCROLL_ALIASES[match[1]] || '';
|
| 257 |
+
const toolName = aliasDirection ? 'scroll' : match[1];
|
| 258 |
+
if (!allowedNames.has(toolName)) return [];
|
| 259 |
+
const args = Object.create(null);
|
| 260 |
+
if (match[2].trim()) {
|
| 261 |
+
const argParts = splitLfmTopLevel(match[2], ',');
|
| 262 |
+
if (!argParts || argParts.some(arg => !arg.trim())) return [];
|
| 263 |
+
for (const arg of argParts) {
|
| 264 |
+
const assignment = splitLfmTopLevel(arg, '=');
|
| 265 |
+
if (!assignment || assignment.length !== 2) return [];
|
| 266 |
+
const key = assignment[0].trim();
|
| 267 |
+
if (!/^[A-Za-z_]\w*$/.test(key) || Object.hasOwn(args, key)) return [];
|
| 268 |
+
const parsed = parseLfmValue(assignment[1]);
|
| 269 |
+
if (!parsed.ok) return [];
|
| 270 |
+
args[key] = parsed.value;
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
if (aliasDirection) {
|
| 274 |
+
if (Object.hasOwn(args, 'direction') && args.direction !== aliasDirection) return [];
|
| 275 |
+
args.direction = aliasDirection;
|
| 276 |
+
}
|
| 277 |
+
calls.push({ name: toolName, arguments: args });
|
| 278 |
+
}
|
| 279 |
+
return calls;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
/**
|
| 283 |
+
* Quote relaxed `key:` tokens only when they occur outside JSON strings and
|
| 284 |
+
* after an object boundary. A regular-expression replacement corrupts string
|
| 285 |
+
* values such as "Keep, status: pending" before JSON.parse sees them.
|
| 286 |
+
*/
|
| 287 |
+
function quoteBareJsonKeys(body) {
|
| 288 |
+
const source = String(body || '');
|
| 289 |
+
let output = '';
|
| 290 |
+
let inString = false;
|
| 291 |
+
let escaped = false;
|
| 292 |
+
|
| 293 |
+
for (let i = 0; i < source.length;) {
|
| 294 |
+
const char = source[i];
|
| 295 |
+
if (inString) {
|
| 296 |
+
output += char;
|
| 297 |
+
if (escaped) escaped = false;
|
| 298 |
+
else if (char === '\\') escaped = true;
|
| 299 |
+
else if (char === '"') inString = false;
|
| 300 |
+
i++;
|
| 301 |
+
continue;
|
| 302 |
+
}
|
| 303 |
+
if (char === '"') {
|
| 304 |
+
inString = true;
|
| 305 |
+
output += char;
|
| 306 |
+
i++;
|
| 307 |
+
continue;
|
| 308 |
+
}
|
| 309 |
+
if (/\w/.test(char)) {
|
| 310 |
+
let previous = i - 1;
|
| 311 |
+
while (previous >= 0 && /\s/.test(source[previous])) previous--;
|
| 312 |
+
if (previous < 0 || source[previous] === '{' || source[previous] === ',') {
|
| 313 |
+
let keyEnd = i + 1;
|
| 314 |
+
while (keyEnd < source.length && /\w/.test(source[keyEnd])) keyEnd++;
|
| 315 |
+
let colon = keyEnd;
|
| 316 |
+
while (colon < source.length && /\s/.test(source[colon])) colon++;
|
| 317 |
+
if (source[colon] === ':') {
|
| 318 |
+
output += `"${source.slice(i, keyEnd)}"${source.slice(keyEnd, colon + 1)}`;
|
| 319 |
+
i = colon + 1;
|
| 320 |
+
continue;
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
}
|
| 324 |
+
output += char;
|
| 325 |
+
i++;
|
| 326 |
+
}
|
| 327 |
+
return output;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
function toFallbackToolCalls(objects) {
|
| 331 |
+
return objects.map((obj, index) => ({
|
| 332 |
+
id: `fallback_call_${Date.now()}_${index}`,
|
| 333 |
+
type: 'function',
|
| 334 |
+
function: {
|
| 335 |
+
name: obj.name,
|
| 336 |
+
arguments: typeof obj.arguments === 'string'
|
| 337 |
+
? obj.arguments
|
| 338 |
+
: JSON.stringify(obj.arguments || obj.parameters || {}),
|
| 339 |
+
},
|
| 340 |
+
}));
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
/**
|
| 344 |
+
* Parse common text tool-call formats into OpenAI-style tool call objects.
|
| 345 |
+
* Only names in allowedNames are accepted.
|
| 346 |
+
*/
|
| 347 |
+
export function parseToolCallsFromText(text, allowedNames) {
|
| 348 |
+
if (!text || text.length > 10000) return [];
|
| 349 |
+
|
| 350 |
+
const lfmCalls = parseLfmToolCalls(text, allowedNames);
|
| 351 |
+
if (lfmCalls !== null) return toFallbackToolCalls(lfmCalls);
|
| 352 |
+
|
| 353 |
+
const wholeResponseArray = parseWholeResponseJsonArray(text, allowedNames);
|
| 354 |
+
if (wholeResponseArray !== null) {
|
| 355 |
+
return toFallbackToolCalls(wholeResponseArray);
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
const results = [];
|
| 359 |
+
const parseXmlParamValue = (value) => {
|
| 360 |
+
const raw = String(value || '');
|
| 361 |
+
// MiniCPM5 wraps values containing <, &, or newlines in CDATA. Extract
|
| 362 |
+
// the literal content first so the tag strip below does not eat it.
|
| 363 |
+
const cdataMatch = /^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/.exec(raw);
|
| 364 |
+
if (cdataMatch) return cdataMatch[1];
|
| 365 |
+
const cleaned = raw
|
| 366 |
+
.replace(/<[^>]+>/g, '')
|
| 367 |
+
.trim();
|
| 368 |
+
if (!cleaned) return '';
|
| 369 |
+
try {
|
| 370 |
+
if (/^(?:"|'.*'|\{|\[|-?\d|true\b|false\b|null\b)/i.test(cleaned)) {
|
| 371 |
+
return JSON.parse(cleaned.replace(/^'([\s\S]*)'$/, '"$1"'));
|
| 372 |
+
}
|
| 373 |
+
} catch { /* fall through to string cleanup */ }
|
| 374 |
+
return cleaned.replace(/^["']+|["']+$/g, '');
|
| 375 |
+
};
|
| 376 |
+
const parseBailingToolCall = (inner) => {
|
| 377 |
+
const nameMatch = /^([A-Za-z_]\w*)/.exec(inner);
|
| 378 |
+
if (!nameMatch || !allowedNames.has(nameMatch[1])) return null;
|
| 379 |
+
let cursor = nameMatch[0].length;
|
| 380 |
+
const args = {};
|
| 381 |
+
const pairRe = /<arg_key>\s*([A-Za-z_]\w*)\s*<\/arg_key>\s*<arg_value>\s*([\s\S]*?)\s*<\/arg_value>/giy;
|
| 382 |
+
while (cursor < inner.length) {
|
| 383 |
+
while (cursor < inner.length && /\s/.test(inner[cursor])) cursor++;
|
| 384 |
+
if (cursor >= inner.length) break;
|
| 385 |
+
pairRe.lastIndex = cursor;
|
| 386 |
+
const pair = pairRe.exec(inner);
|
| 387 |
+
if (!pair || pair.index !== cursor) return null;
|
| 388 |
+
args[pair[1]] = parseXmlParamValue(pair[2]);
|
| 389 |
+
cursor = pairRe.lastIndex;
|
| 390 |
+
}
|
| 391 |
+
return { name: nameMatch[1], arguments: args };
|
| 392 |
+
};
|
| 393 |
+
|
| 394 |
+
const patterns = [
|
| 395 |
+
/<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/gi,
|
| 396 |
+
/<\|tool_call\|?>\s*([\s\S]*?)\s*<\|?\/?tool_call\|?>/gi,
|
| 397 |
+
/<functioncall>\s*([\s\S]*?)\s*<\/functioncall>/gi,
|
| 398 |
+
];
|
| 399 |
+
|
| 400 |
+
for (const re of patterns) {
|
| 401 |
+
let match;
|
| 402 |
+
while ((match = re.exec(text)) !== null) {
|
| 403 |
+
const inner = match[1].trim();
|
| 404 |
+
const wrappedArray = parseWholeResponseJsonArray(inner, allowedNames);
|
| 405 |
+
if (wrappedArray !== null) {
|
| 406 |
+
results.push(...wrappedArray);
|
| 407 |
+
continue;
|
| 408 |
+
}
|
| 409 |
+
try {
|
| 410 |
+
const obj = JSON.parse(inner);
|
| 411 |
+
if (obj && obj.name && allowedNames.has(obj.name)) {
|
| 412 |
+
results.push(obj);
|
| 413 |
+
continue;
|
| 414 |
+
}
|
| 415 |
+
} catch { /* not JSON — try call:name{} format below */ }
|
| 416 |
+
|
| 417 |
+
// Ling/Bailing V3 native tool format:
|
| 418 |
+
// <tool_call>click_ax\n<arg_key>ref_id</arg_key>\n<arg_value>ref_7</arg_value></tool_call>
|
| 419 |
+
const bailingCall = parseBailingToolCall(inner);
|
| 420 |
+
if (bailingCall) {
|
| 421 |
+
results.push(bailingCall);
|
| 422 |
+
continue;
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
const callMatch = /^call:(\w+)\s*\{([\s\S]*)\}$/.exec(inner);
|
| 426 |
+
if (callMatch && allowedNames.has(callMatch[1])) {
|
| 427 |
+
const toolName = callMatch[1];
|
| 428 |
+
let argsBody = callMatch[2]
|
| 429 |
+
.replace(/<\|"\|>/g, '"')
|
| 430 |
+
.replace(/<\|'\\?\|>/g, "'");
|
| 431 |
+
argsBody = quoteBareJsonKeys(argsBody);
|
| 432 |
+
try {
|
| 433 |
+
const args = JSON.parse(`{${argsBody}}`);
|
| 434 |
+
results.push({ name: toolName, arguments: args });
|
| 435 |
+
} catch { /* malformed arguments must never dispatch */ }
|
| 436 |
+
}
|
| 437 |
+
}
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
// XML-ish tool-call format used by some local/chat-template models:
|
| 441 |
+
// <tool_call><function=click_ax><parameter=ref_id>ref_6</parameter>...
|
| 442 |
+
const xmlToolRe = /<tool_call>\s*<function(?:\s*=\s*["']?([A-Za-z_]\w*)["']?|\s+name\s*=\s*["']?([A-Za-z_]\w*)["']?)\s*>\s*([\s\S]*?)\s*<\/function>\s*<\/tool_call>/gi;
|
| 443 |
+
const xmlToolSpans = [];
|
| 444 |
+
let xmlMatch;
|
| 445 |
+
while ((xmlMatch = xmlToolRe.exec(text)) !== null) {
|
| 446 |
+
xmlToolSpans.push({ start: xmlMatch.index, end: xmlMatch.index + xmlMatch[0].length });
|
| 447 |
+
const toolName = xmlMatch[1] || xmlMatch[2];
|
| 448 |
+
if (!allowedNames.has(toolName)) continue;
|
| 449 |
+
const body = xmlMatch[3] || '';
|
| 450 |
+
const args = {};
|
| 451 |
+
const paramRe = /<(?:param|parameter)(?:\s*=\s*["']?([A-Za-z_]\w*)["']?|\s+name\s*=\s*["']?([A-Za-z_]\w*)["']?)\s*>\s*([\s\S]*?)\s*<\/(?:param|parameter)>/gi;
|
| 452 |
+
let paramMatch;
|
| 453 |
+
while ((paramMatch = paramRe.exec(body)) !== null) {
|
| 454 |
+
const key = paramMatch[1] || paramMatch[2];
|
| 455 |
+
if (!key) continue;
|
| 456 |
+
args[key] = parseXmlParamValue(paramMatch[3]);
|
| 457 |
+
}
|
| 458 |
+
results.push({ name: toolName, arguments: args });
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
// MiniCPM5-2B native tool format (no outer <tool_call> wrapper):
|
| 462 |
+
// <function name="click"><param name="ref_id">ref_6</param>...</function>
|
| 463 |
+
const minicpmFunctionRe = /<function(?:\s+name\s*=\s*["']([A-Za-z_]\w*)["']|\s*=\s*["']?([A-Za-z_]\w*)["']?)\s*>\s*([\s\S]*?)\s*<\/function>/gi;
|
| 464 |
+
let minicpmMatch;
|
| 465 |
+
while ((minicpmMatch = minicpmFunctionRe.exec(text)) !== null) {
|
| 466 |
+
// Skip functions already consumed inside a <tool_call> wrapper above.
|
| 467 |
+
if (xmlToolSpans.some(span => minicpmMatch.index >= span.start && minicpmMatch.index < span.end)) continue;
|
| 468 |
+
const toolName = minicpmMatch[1] || minicpmMatch[2];
|
| 469 |
+
if (!allowedNames.has(toolName)) continue;
|
| 470 |
+
const body = minicpmMatch[3] || '';
|
| 471 |
+
const args = {};
|
| 472 |
+
const paramRe = /<(?:param|parameter)(?:\s*=\s*["']?([A-Za-z_]\w*)["']?|\s+name\s*=\s*["']?([A-Za-z_]\w*)["']?)\s*>\s*([\s\S]*?)\s*<\/(?:param|parameter)>/gi;
|
| 473 |
+
let paramMatch;
|
| 474 |
+
while ((paramMatch = paramRe.exec(body)) !== null) {
|
| 475 |
+
const key = paramMatch[1] || paramMatch[2];
|
| 476 |
+
if (!key) continue;
|
| 477 |
+
args[key] = parseXmlParamValue(paramMatch[3]);
|
| 478 |
+
}
|
| 479 |
+
results.push({ name: toolName, arguments: args });
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
if (results.length === 0) {
|
| 483 |
+
for (const { start, end } of extractBalancedJsonSpans(text)) {
|
| 484 |
+
if (!standsAloneOnLine(text, start, end)) continue;
|
| 485 |
+
try {
|
| 486 |
+
const obj = JSON.parse(text.slice(start, end + 1));
|
| 487 |
+
if (obj && obj.name && allowedNames.has(obj.name)) {
|
| 488 |
+
results.push(obj);
|
| 489 |
+
}
|
| 490 |
+
} catch { /* skip */ }
|
| 491 |
+
}
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
if (results.length === 0) {
|
| 495 |
+
const callRe = /call:(\w+)\s*\{([\s\S]*?)\}/g;
|
| 496 |
+
let match;
|
| 497 |
+
while ((match = callRe.exec(text)) !== null) {
|
| 498 |
+
if (!allowedNames.has(match[1])) continue;
|
| 499 |
+
const toolName = match[1];
|
| 500 |
+
let argsBody = match[2]
|
| 501 |
+
.replace(/<\|"\|>/g, '"')
|
| 502 |
+
.replace(/<\|'\\?\|>/g, "'");
|
| 503 |
+
argsBody = quoteBareJsonKeys(argsBody);
|
| 504 |
+
try {
|
| 505 |
+
const args = JSON.parse(`{${argsBody}}`);
|
| 506 |
+
results.push({ name: toolName, arguments: args });
|
| 507 |
+
} catch { /* malformed arguments must never dispatch */ }
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
return toFallbackToolCalls(results);
|
| 512 |
+
}
|
runtime/vendor/LICENSE.onnxruntime.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) Microsoft Corporation
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
runtime/vendor/LICENSE.transformers.txt
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright [yyyy] [name of copyright owner]
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
runtime/vendor/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Vendored Transformers.js WebGPU runtime
|
| 2 |
+
|
| 3 |
+
This directory packages the JavaScript and WASM runtime used by two local
|
| 4 |
+
WebGPU paths in Chrome and by offline RAG's CPU/WASM semantic reranker:
|
| 5 |
+
|
| 6 |
+
- **Apocalypse Mode -> local WebGPU chat** downloads the selected LFM2.5 text
|
| 7 |
+
or vision-language preset, or the Nanbeige4.2-3B ONNX export, used by the
|
| 8 |
+
standalone-chat nuclear override. An opt-in Bonsai 27B preset uses a separate
|
| 9 |
+
vendored bitgpu worker, not this Transformers.js runtime; see
|
| 10 |
+
`src/chrome/vendor/bitgpu/README.webbrain.md`.
|
| 11 |
+
- **Settings -> Multimodal -> Vision -> LFM2.5-VL local fallback** runs
|
| 12 |
+
`LiquidAI/LFM2.5-VL-450M-ONNX` as the dedicated screenshot sidecar.
|
| 13 |
+
- **Apocalypse Mode -> Offline RAG** runs the explicitly downloaded, pinned
|
| 14 |
+
`Xenova/multilingual-e5-small` q8 model in a separate CPU/WASM worker. Model
|
| 15 |
+
weights remain optional and are never bundled or downloaded by a question.
|
| 16 |
+
|
| 17 |
+
Model weights are not bundled. Transformers.js downloads each selected WebGPU
|
| 18 |
+
model on first use and stores it in the browser cache. The shipped ONNX chat
|
| 19 |
+
presets are LFM2.5 2.6B, 1.2B Instruct, 1.2B Thinking, VL 1.6B, VL 3B, and
|
| 20 |
+
Nanbeige4.2-3B.
|
| 21 |
+
They are available through the nuclear control in standalone chat and can also
|
| 22 |
+
be selected as the normal provider after download. The reasoning presets keep
|
| 23 |
+
completed thinking out of visible answers. Current LFM2.5-VL layouts use:
|
| 24 |
+
|
| 25 |
+
- `embed_tokens`: FP16
|
| 26 |
+
- `vision_encoder`: FP16
|
| 27 |
+
- `decoder_model_merged`: Q4
|
| 28 |
+
|
| 29 |
+
`Michionlion/Nanbeige4.2-3B-ONNX-WebGPU` needs no bundle patch, but it does
|
| 30 |
+
need two things from this runtime. It publishes one WebGPU-fused graph named
|
| 31 |
+
`onnx/model_webgpu_mlp_q4f16.onnx` instead of the default `model_q4f16.onnx`,
|
| 32 |
+
so the worker passes `model_file_name: 'model_webgpu_mlp'`; the two external
|
| 33 |
+
data shards are declared by the repository's own
|
| 34 |
+
`transformers.js_config.use_external_data_format`. Its graph also uses the
|
| 35 |
+
`com.microsoft::MatMulNBitsMlp` WebGPU kernel, which is compiled into the
|
| 36 |
+
vendored `ort-wasm-simd-threaded.asyncify.wasm`. Do not replace the ONNX
|
| 37 |
+
Runtime artifacts with a build that drops that kernel; a test asserts it is
|
| 38 |
+
present because its absence only shows up as an opaque session-creation
|
| 39 |
+
failure at runtime.
|
| 40 |
+
|
| 41 |
+
The dedicated 450M vision sidecar uses the same component layout and is
|
| 42 |
+
approximately 810 MB. The VL 1.6B chat export instead names its vision and
|
| 43 |
+
decoder components `embed_images` and `decoder`; the compatibility patch below
|
| 44 |
+
maps those files into the standard image-text session names.
|
| 45 |
+
|
| 46 |
+
## Packaged files
|
| 47 |
+
|
| 48 |
+
| File / directory | Source | Purpose |
|
| 49 |
+
| --- | --- | --- |
|
| 50 |
+
| `transformers.web.js` | `@huggingface/transformers` 4.2.0 | Browser ESM model/processor APIs |
|
| 51 |
+
| `ort.webgpu.mjs` | `onnxruntime-web` 1.27.0 | WebGPU execution provider |
|
| 52 |
+
| `onnxruntime-common/` | matching `onnxruntime-common` dependency | Tensor and session types |
|
| 53 |
+
| `ort-wasm-simd-threaded.asyncify.*` | `onnxruntime-web` 1.27.0 | The only WASM bridge; carries the WebGPU/JSEP runtime |
|
| 54 |
+
| `LICENSE.transformers.txt` | `@huggingface/transformers` 4.2.0 | Apache-2.0 license |
|
| 55 |
+
| `LICENSE.onnxruntime.txt` | ONNX Runtime 1.27.0 | MIT license |
|
| 56 |
+
| `ThirdPartyNotices.onnxruntime.txt` | ONNX Runtime 1.27.0 | Notices for incorporated third-party software |
|
| 57 |
+
|
| 58 |
+
The readable, unminified browser builds are committed so a fresh checkout is a
|
| 59 |
+
complete, Chrome Web Store-reviewable extension. Remote executable code is not
|
| 60 |
+
allowed by Manifest V3 CSP; only model/config/tokenizer data is fetched from
|
| 61 |
+
Hugging Face.
|
| 62 |
+
|
| 63 |
+
Only the asyncify variant is vendored. `ort.webgpu.mjs` resolves its WASM
|
| 64 |
+
filename from flags fixed at ONNX Runtime build time, and in this build the jsep
|
| 65 |
+
and jspi branches are compiled out, so `ort-wasm-simd-threaded.asyncify.*` is the
|
| 66 |
+
only bridge that can ever load. The WebGPU/JSEP execution provider lives inside
|
| 67 |
+
that artifact; it is not a separate download. Copying the `jsep` or `jspi` pair
|
| 68 |
+
adds tens of megabytes of unreachable binary to the reviewed package, so do not
|
| 69 |
+
restore them without first checking that filename branch.
|
| 70 |
+
|
| 71 |
+
The ONNX Runtime files are intentionally newer than the version pinned by
|
| 72 |
+
Transformers.js 4.2.0. Stable 1.27.0 contains WebGPU buffer-pool and
|
| 73 |
+
Qwen3/QMoE correctness fixes needed by Ling while retaining the same public
|
| 74 |
+
JavaScript session API used by this Transformers.js release.
|
| 75 |
+
|
| 76 |
+
## Browser bundle patches
|
| 77 |
+
|
| 78 |
+
The upstream browser bundle contains two bare module specifiers that an
|
| 79 |
+
unbundled extension cannot resolve. After copying a new release, rewrite them:
|
| 80 |
+
|
| 81 |
+
```bash
|
| 82 |
+
sed -i 's|"onnxruntime-web/webgpu"|"./ort.webgpu.mjs"|' \
|
| 83 |
+
src/chrome/vendor/transformers/transformers.web.js
|
| 84 |
+
sed -i 's|"onnxruntime-common"|"./onnxruntime-common/index.js"|' \
|
| 85 |
+
src/chrome/vendor/transformers/transformers.web.js
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
Verify that no executable bare imports remain:
|
| 89 |
+
|
| 90 |
+
```bash
|
| 91 |
+
grep -E '(import|export)[^"]*from\s+"[a-zA-Z@]' \
|
| 92 |
+
src/chrome/vendor/transformers/transformers.web.js \
|
| 93 |
+
| grep -v '^\s*//' | grep -v '^\s*\*'
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
The LFM2.5-VL ONNX repositories need two compatibility hooks. The 1.6B export
|
| 97 |
+
predates the standard ImageTextToText component filenames, so keep the small
|
| 98 |
+
`session_file_names` alias hook in
|
| 99 |
+
`MODEL_SESSION_CONFIG[MODEL_TYPES.ImageTextToText]`; the worker supplies aliases
|
| 100 |
+
through `config["transformers.js_config"]`. Keep the corresponding `getSession`
|
| 101 |
+
logic resolving device and dtype by logical `session_name`, while using the
|
| 102 |
+
aliased filename only to fetch the physical ONNX graph. Both current VL exports
|
| 103 |
+
also use the Transformers v5 processor layout: image metadata is nested in
|
| 104 |
+
`processor_config.json`, and the chat template lives in `chat_template.jinja`.
|
| 105 |
+
Keep `loadImageProcessorConfig`, `image_processor_config_file`, and
|
| 106 |
+
`chat_template_file` support so the worker can opt into that layout without
|
| 107 |
+
changing older models. Reapply these patches after replacing
|
| 108 |
+
`transformers.web.js`, and mirror the resulting browser bundle into Firefox so
|
| 109 |
+
the packaged vendor files remain byte-identical.
|
| 110 |
+
|
| 111 |
+
## Updating
|
| 112 |
+
|
| 113 |
+
Use a temporary dependency install; WebBrain does not need a runtime npm
|
| 114 |
+
dependency because the reviewed browser assets are committed directly:
|
| 115 |
+
|
| 116 |
+
```bash
|
| 117 |
+
npm install --no-save @huggingface/transformers@latest
|
| 118 |
+
cp node_modules/@huggingface/transformers/dist/transformers.web.js \
|
| 119 |
+
src/chrome/vendor/transformers/
|
| 120 |
+
cp node_modules/onnxruntime-web/dist/ort.webgpu.mjs \
|
| 121 |
+
src/chrome/vendor/transformers/
|
| 122 |
+
cp node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.asyncify.{mjs,wasm} \
|
| 123 |
+
src/chrome/vendor/transformers/
|
| 124 |
+
rm -rf src/chrome/vendor/transformers/onnxruntime-common
|
| 125 |
+
mkdir src/chrome/vendor/transformers/onnxruntime-common
|
| 126 |
+
cp node_modules/onnxruntime-common/dist/esm/*.js \
|
| 127 |
+
src/chrome/vendor/transformers/onnxruntime-common/
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
Copy the Transformers.js license and the ONNX Runtime license plus
|
| 131 |
+
`ThirdPartyNotices.txt` into this directory whenever the runtime is updated.
|
| 132 |
+
Reapply the specifier and ImageTextToText session-alias patches, update the
|
| 133 |
+
version table above, then verify:
|
| 134 |
+
|
| 135 |
+
1. `node --check` passes for the provider, host, and worker.
|
| 136 |
+
2. **Use local fallback** enables the option without downloading weights.
|
| 137 |
+
3. **Test Connection** reads `WB7` from the packaged vision probe image.
|
| 138 |
+
4. The second test reuses browser-cached model files.
|
| 139 |
+
|
| 140 |
+
## Runtime architecture
|
| 141 |
+
|
| 142 |
+
```text
|
| 143 |
+
ProviderManager._createProvider('webgpu') / getVisionProvider()
|
| 144 |
+
-> WebGPUProvider.chat() / WebGPUVisionProvider.chat()
|
| 145 |
+
-> MV3 offscreen document
|
| 146 |
+
-> dedicated module Worker
|
| 147 |
+
-> text-generation pipeline / AutoProcessor + AutoModelForImageTextToText
|
| 148 |
+
-> selected LFM2.5 or Nanbeige ONNX repo / LFM2.5-VL-450M-ONNX over WebGPU
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
Keep inference in the Worker. The MV3 service worker has no WebGPU, while the
|
| 152 |
+
offscreen document's main thread has shown tighter WASM allocation limits for
|
| 153 |
+
large ONNX runs. Do not set `preferredOutputLocation: 'gpu-buffer'` on this
|
| 154 |
+
generation path: Transformers.js decodes the generated tensor on the CPU and
|
| 155 |
+
must be allowed to download that output normally.
|
| 156 |
+
|
| 157 |
+
LFM2.5-VL expects the image placeholder before the user's text in its chat
|
| 158 |
+
template. The Worker normalizes incoming OpenAI-style multimodal messages to
|
| 159 |
+
that order. For the connection test, it replaces the packaged generic OCR image
|
| 160 |
+
with three large, unlabeled color panels. This proves the local model received
|
| 161 |
+
pixels without relying on fine OCR, which is brittle for a 450M model. Normal
|
| 162 |
+
screenshots are never replaced by this probe-only path.
|
runtime/vendor/ThirdPartyNotices.onnxruntime.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
runtime/vendor/onnxruntime-common/backend-impl.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
const backends = new Map();
|
| 4 |
+
const backendsSortedByPriority = [];
|
| 5 |
+
/**
|
| 6 |
+
* Register a backend.
|
| 7 |
+
*
|
| 8 |
+
* @param name - the name as a key to lookup as an execution provider.
|
| 9 |
+
* @param backend - the backend object.
|
| 10 |
+
* @param priority - an integer indicating the priority of the backend. Higher number means higher priority. if priority
|
| 11 |
+
* < 0, it will be considered as a 'beta' version and will not be used as a fallback backend by default.
|
| 12 |
+
*
|
| 13 |
+
* @ignore
|
| 14 |
+
*/
|
| 15 |
+
export const registerBackend = (name, backend, priority) => {
|
| 16 |
+
if (backend && typeof backend.init === 'function' && typeof backend.createInferenceSessionHandler === 'function') {
|
| 17 |
+
const currentBackend = backends.get(name);
|
| 18 |
+
if (currentBackend === undefined) {
|
| 19 |
+
backends.set(name, { backend, priority });
|
| 20 |
+
}
|
| 21 |
+
else if (currentBackend.priority > priority) {
|
| 22 |
+
// same name is already registered with a higher priority. skip registeration.
|
| 23 |
+
return;
|
| 24 |
+
}
|
| 25 |
+
else if (currentBackend.priority === priority) {
|
| 26 |
+
if (currentBackend.backend !== backend) {
|
| 27 |
+
throw new Error(`cannot register backend "${name}" using priority ${priority}`);
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
if (priority >= 0) {
|
| 31 |
+
const i = backendsSortedByPriority.indexOf(name);
|
| 32 |
+
if (i !== -1) {
|
| 33 |
+
backendsSortedByPriority.splice(i, 1);
|
| 34 |
+
}
|
| 35 |
+
for (let i = 0; i < backendsSortedByPriority.length; i++) {
|
| 36 |
+
if (backends.get(backendsSortedByPriority[i]).priority <= priority) {
|
| 37 |
+
backendsSortedByPriority.splice(i, 0, name);
|
| 38 |
+
return;
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
backendsSortedByPriority.push(name);
|
| 42 |
+
}
|
| 43 |
+
return;
|
| 44 |
+
}
|
| 45 |
+
throw new TypeError('not a valid backend');
|
| 46 |
+
};
|
| 47 |
+
/**
|
| 48 |
+
* Try to resolve and initialize a backend.
|
| 49 |
+
*
|
| 50 |
+
* @param backendName - the name of the backend.
|
| 51 |
+
* @returns the backend instance if resolved and initialized successfully, or an error message if failed.
|
| 52 |
+
*/
|
| 53 |
+
const tryResolveAndInitializeBackend = async (backendName) => {
|
| 54 |
+
const backendInfo = backends.get(backendName);
|
| 55 |
+
if (!backendInfo) {
|
| 56 |
+
return 'backend not found.';
|
| 57 |
+
}
|
| 58 |
+
if (backendInfo.initialized) {
|
| 59 |
+
return backendInfo.backend;
|
| 60 |
+
}
|
| 61 |
+
else if (backendInfo.aborted) {
|
| 62 |
+
return backendInfo.error;
|
| 63 |
+
}
|
| 64 |
+
else {
|
| 65 |
+
const isInitializing = !!backendInfo.initPromise;
|
| 66 |
+
try {
|
| 67 |
+
if (!isInitializing) {
|
| 68 |
+
backendInfo.initPromise = backendInfo.backend.init(backendName);
|
| 69 |
+
}
|
| 70 |
+
await backendInfo.initPromise;
|
| 71 |
+
backendInfo.initialized = true;
|
| 72 |
+
return backendInfo.backend;
|
| 73 |
+
}
|
| 74 |
+
catch (e) {
|
| 75 |
+
if (!isInitializing) {
|
| 76 |
+
backendInfo.error = `${e}`;
|
| 77 |
+
backendInfo.aborted = true;
|
| 78 |
+
}
|
| 79 |
+
return backendInfo.error;
|
| 80 |
+
}
|
| 81 |
+
finally {
|
| 82 |
+
delete backendInfo.initPromise;
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
};
|
| 86 |
+
/**
|
| 87 |
+
* Resolve execution providers from the specific session options.
|
| 88 |
+
*
|
| 89 |
+
* @param options - the session options object.
|
| 90 |
+
* @returns a promise that resolves to a tuple of an initialized backend instance and a session options object with
|
| 91 |
+
* filtered EP list.
|
| 92 |
+
*
|
| 93 |
+
* @ignore
|
| 94 |
+
*/
|
| 95 |
+
export const resolveBackendAndExecutionProviders = async (options) => {
|
| 96 |
+
// extract backend hints from session options
|
| 97 |
+
const eps = options.executionProviders || [];
|
| 98 |
+
const backendHints = eps.map((i) => (typeof i === 'string' ? i : i.name));
|
| 99 |
+
const backendNames = backendHints.length === 0 ? backendsSortedByPriority : backendHints;
|
| 100 |
+
// try to resolve and initialize all requested backends
|
| 101 |
+
let backend;
|
| 102 |
+
const errors = [];
|
| 103 |
+
const availableBackendNames = new Set();
|
| 104 |
+
for (const backendName of backendNames) {
|
| 105 |
+
const resolveResult = await tryResolveAndInitializeBackend(backendName);
|
| 106 |
+
if (typeof resolveResult === 'string') {
|
| 107 |
+
errors.push({ name: backendName, err: resolveResult });
|
| 108 |
+
}
|
| 109 |
+
else {
|
| 110 |
+
if (!backend) {
|
| 111 |
+
backend = resolveResult;
|
| 112 |
+
}
|
| 113 |
+
if (backend === resolveResult) {
|
| 114 |
+
availableBackendNames.add(backendName);
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
// if no backend is available, throw error.
|
| 119 |
+
if (!backend) {
|
| 120 |
+
throw new Error(`no available backend found. ERR: ${errors.map((e) => `[${e.name}] ${e.err}`).join(', ')}`);
|
| 121 |
+
}
|
| 122 |
+
// for each explicitly requested backend, if it's not available, output warning message.
|
| 123 |
+
for (const { name, err } of errors) {
|
| 124 |
+
if (backendHints.includes(name)) {
|
| 125 |
+
// eslint-disable-next-line no-console
|
| 126 |
+
console.warn(`removing requested execution provider "${name}" from session options because it is not available: ${err}`);
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
const filteredEps = eps.filter((i) => availableBackendNames.has(typeof i === 'string' ? i : i.name));
|
| 130 |
+
return [
|
| 131 |
+
backend,
|
| 132 |
+
new Proxy(options, {
|
| 133 |
+
get: (target, prop) => {
|
| 134 |
+
if (prop === 'executionProviders') {
|
| 135 |
+
return filteredEps;
|
| 136 |
+
}
|
| 137 |
+
return Reflect.get(target, prop);
|
| 138 |
+
},
|
| 139 |
+
}),
|
| 140 |
+
];
|
| 141 |
+
};
|
| 142 |
+
//# sourceMappingURL=backend-impl.js.map
|
runtime/vendor/onnxruntime-common/backend.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export { registerBackend } from './backend-impl.js';
|
| 4 |
+
//# sourceMappingURL=backend.js.map
|
runtime/vendor/onnxruntime-common/env-impl.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { version } from './version.js';
|
| 4 |
+
let logLevelValue = 'warning';
|
| 5 |
+
export const env = {
|
| 6 |
+
wasm: {},
|
| 7 |
+
webgl: {},
|
| 8 |
+
webgpu: {},
|
| 9 |
+
versions: { common: version },
|
| 10 |
+
set logLevel(value) {
|
| 11 |
+
if (value === undefined) {
|
| 12 |
+
return;
|
| 13 |
+
}
|
| 14 |
+
if (typeof value !== 'string' || ['verbose', 'info', 'warning', 'error', 'fatal'].indexOf(value) === -1) {
|
| 15 |
+
throw new Error(`Unsupported logging level: ${value}`);
|
| 16 |
+
}
|
| 17 |
+
logLevelValue = value;
|
| 18 |
+
},
|
| 19 |
+
get logLevel() {
|
| 20 |
+
return logLevelValue;
|
| 21 |
+
},
|
| 22 |
+
};
|
| 23 |
+
// set property 'logLevel' so that they can be correctly transferred to worker by `postMessage()`.
|
| 24 |
+
Object.defineProperty(env, 'logLevel', { enumerable: true });
|
| 25 |
+
//# sourceMappingURL=env-impl.js.map
|
runtime/vendor/onnxruntime-common/env.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { env as envImpl } from './env-impl.js';
|
| 4 |
+
/**
|
| 5 |
+
* Represent a set of flags as a global singleton.
|
| 6 |
+
*/
|
| 7 |
+
export const env = envImpl;
|
| 8 |
+
//# sourceMappingURL=env.js.map
|
runtime/vendor/onnxruntime-common/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
/**
|
| 4 |
+
* # ONNX Runtime JavaScript API
|
| 5 |
+
*
|
| 6 |
+
* ONNX Runtime JavaScript API is a unified API for all JavaScript usages, including the following NPM packages:
|
| 7 |
+
*
|
| 8 |
+
* - [onnxruntime-node](https://www.npmjs.com/package/onnxruntime-node)
|
| 9 |
+
* - [onnxruntime-web](https://www.npmjs.com/package/onnxruntime-web)
|
| 10 |
+
* - [onnxruntime-react-native](https://www.npmjs.com/package/onnxruntime-react-native)
|
| 11 |
+
*
|
| 12 |
+
* See also:
|
| 13 |
+
* - [Get Started](https://onnxruntime.ai/docs/get-started/with-javascript/)
|
| 14 |
+
* - [Inference examples](https://github.com/microsoft/onnxruntime-inference-examples/tree/main/js)
|
| 15 |
+
*
|
| 16 |
+
* @packageDocumentation
|
| 17 |
+
*/
|
| 18 |
+
export * from './backend.js';
|
| 19 |
+
export * from './env.js';
|
| 20 |
+
export * from './inference-session.js';
|
| 21 |
+
export * from './tensor.js';
|
| 22 |
+
export * from './tensor-conversion.js';
|
| 23 |
+
export * from './tensor-factory.js';
|
| 24 |
+
export * from './trace.js';
|
| 25 |
+
export * from './onnx-model.js';
|
| 26 |
+
export * from './onnx-value.js';
|
| 27 |
+
//# sourceMappingURL=index.js.map
|
runtime/vendor/onnxruntime-common/inference-session-impl.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { resolveBackendAndExecutionProviders } from './backend-impl.js';
|
| 4 |
+
import { Tensor } from './tensor.js';
|
| 5 |
+
import { TRACE_FUNC_BEGIN, TRACE_FUNC_END, TRACE_EVENT_BEGIN, TRACE_EVENT_END } from './trace.js';
|
| 6 |
+
export class InferenceSession {
|
| 7 |
+
constructor(handler) {
|
| 8 |
+
this.handler = handler;
|
| 9 |
+
}
|
| 10 |
+
async run(feeds, arg1, arg2) {
|
| 11 |
+
TRACE_FUNC_BEGIN();
|
| 12 |
+
TRACE_EVENT_BEGIN('InferenceSession.run');
|
| 13 |
+
const fetches = {};
|
| 14 |
+
let options = {};
|
| 15 |
+
// check inputs
|
| 16 |
+
if (typeof feeds !== 'object' || feeds === null || feeds instanceof Tensor || Array.isArray(feeds)) {
|
| 17 |
+
throw new TypeError("'feeds' must be an object that use input names as keys and OnnxValue as corresponding values.");
|
| 18 |
+
}
|
| 19 |
+
let isFetchesEmpty = true;
|
| 20 |
+
// determine which override is being used
|
| 21 |
+
if (typeof arg1 === 'object') {
|
| 22 |
+
if (arg1 === null) {
|
| 23 |
+
throw new TypeError('Unexpected argument[1]: cannot be null.');
|
| 24 |
+
}
|
| 25 |
+
if (arg1 instanceof Tensor) {
|
| 26 |
+
throw new TypeError("'fetches' cannot be a Tensor");
|
| 27 |
+
}
|
| 28 |
+
if (Array.isArray(arg1)) {
|
| 29 |
+
if (arg1.length === 0) {
|
| 30 |
+
throw new TypeError("'fetches' cannot be an empty array.");
|
| 31 |
+
}
|
| 32 |
+
isFetchesEmpty = false;
|
| 33 |
+
// output names
|
| 34 |
+
for (const name of arg1) {
|
| 35 |
+
if (typeof name !== 'string') {
|
| 36 |
+
throw new TypeError("'fetches' must be a string array or an object.");
|
| 37 |
+
}
|
| 38 |
+
if (this.outputNames.indexOf(name) === -1) {
|
| 39 |
+
throw new RangeError(`'fetches' contains invalid output name: ${name}.`);
|
| 40 |
+
}
|
| 41 |
+
fetches[name] = null;
|
| 42 |
+
}
|
| 43 |
+
if (typeof arg2 === 'object' && arg2 !== null) {
|
| 44 |
+
options = arg2;
|
| 45 |
+
}
|
| 46 |
+
else if (typeof arg2 !== 'undefined') {
|
| 47 |
+
throw new TypeError("'options' must be an object.");
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
else {
|
| 51 |
+
// decide whether arg1 is fetches or options
|
| 52 |
+
// if any output name is present and its value is valid OnnxValue, we consider it fetches
|
| 53 |
+
let isFetches = false;
|
| 54 |
+
const arg1Keys = Object.getOwnPropertyNames(arg1);
|
| 55 |
+
for (const name of this.outputNames) {
|
| 56 |
+
if (arg1Keys.indexOf(name) !== -1) {
|
| 57 |
+
const v = arg1[name];
|
| 58 |
+
if (v === null || v instanceof Tensor) {
|
| 59 |
+
isFetches = true;
|
| 60 |
+
isFetchesEmpty = false;
|
| 61 |
+
fetches[name] = v;
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
if (isFetches) {
|
| 66 |
+
if (typeof arg2 === 'object' && arg2 !== null) {
|
| 67 |
+
options = arg2;
|
| 68 |
+
}
|
| 69 |
+
else if (typeof arg2 !== 'undefined') {
|
| 70 |
+
throw new TypeError("'options' must be an object.");
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
else {
|
| 74 |
+
options = arg1;
|
| 75 |
+
}
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
else if (typeof arg1 !== 'undefined') {
|
| 79 |
+
throw new TypeError("Unexpected argument[1]: must be 'fetches' or 'options'.");
|
| 80 |
+
}
|
| 81 |
+
// check if all inputs are in feed
|
| 82 |
+
for (const name of this.inputNames) {
|
| 83 |
+
if (typeof feeds[name] === 'undefined') {
|
| 84 |
+
throw new Error(`input '${name}' is missing in 'feeds'.`);
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
// if no fetches is specified, we use the full output names list
|
| 88 |
+
if (isFetchesEmpty) {
|
| 89 |
+
for (const name of this.outputNames) {
|
| 90 |
+
fetches[name] = null;
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
// feeds, fetches and options are prepared
|
| 94 |
+
const results = await this.handler.run(feeds, fetches, options);
|
| 95 |
+
const returnValue = {};
|
| 96 |
+
for (const key in results) {
|
| 97 |
+
if (Object.hasOwnProperty.call(results, key)) {
|
| 98 |
+
const result = results[key];
|
| 99 |
+
if (result instanceof Tensor) {
|
| 100 |
+
returnValue[key] = result;
|
| 101 |
+
}
|
| 102 |
+
else {
|
| 103 |
+
returnValue[key] = new Tensor(result.type, result.data, result.dims);
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
TRACE_EVENT_END('InferenceSession.run');
|
| 108 |
+
TRACE_FUNC_END();
|
| 109 |
+
return returnValue;
|
| 110 |
+
}
|
| 111 |
+
async release() {
|
| 112 |
+
return this.handler.dispose();
|
| 113 |
+
}
|
| 114 |
+
static async create(arg0, arg1, arg2, arg3) {
|
| 115 |
+
TRACE_FUNC_BEGIN();
|
| 116 |
+
TRACE_EVENT_BEGIN('InferenceSession.create');
|
| 117 |
+
// either load from a file or buffer
|
| 118 |
+
let filePathOrUint8Array;
|
| 119 |
+
let options = {};
|
| 120 |
+
if (typeof arg0 === 'string') {
|
| 121 |
+
filePathOrUint8Array = arg0;
|
| 122 |
+
if (typeof arg1 === 'object' && arg1 !== null) {
|
| 123 |
+
options = arg1;
|
| 124 |
+
}
|
| 125 |
+
else if (typeof arg1 !== 'undefined') {
|
| 126 |
+
throw new TypeError("'options' must be an object.");
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
else if (arg0 instanceof Uint8Array) {
|
| 130 |
+
filePathOrUint8Array = arg0;
|
| 131 |
+
if (typeof arg1 === 'object' && arg1 !== null) {
|
| 132 |
+
options = arg1;
|
| 133 |
+
}
|
| 134 |
+
else if (typeof arg1 !== 'undefined') {
|
| 135 |
+
throw new TypeError("'options' must be an object.");
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
else if (arg0 instanceof ArrayBuffer ||
|
| 139 |
+
(typeof SharedArrayBuffer !== 'undefined' && arg0 instanceof SharedArrayBuffer)) {
|
| 140 |
+
const buffer = arg0;
|
| 141 |
+
let byteOffset = 0;
|
| 142 |
+
let byteLength = arg0.byteLength;
|
| 143 |
+
if (typeof arg1 === 'object' && arg1 !== null) {
|
| 144 |
+
options = arg1;
|
| 145 |
+
}
|
| 146 |
+
else if (typeof arg1 === 'number') {
|
| 147 |
+
byteOffset = arg1;
|
| 148 |
+
if (!Number.isSafeInteger(byteOffset)) {
|
| 149 |
+
throw new RangeError("'byteOffset' must be an integer.");
|
| 150 |
+
}
|
| 151 |
+
if (byteOffset < 0 || byteOffset >= buffer.byteLength) {
|
| 152 |
+
throw new RangeError(`'byteOffset' is out of range [0, ${buffer.byteLength}).`);
|
| 153 |
+
}
|
| 154 |
+
byteLength = arg0.byteLength - byteOffset;
|
| 155 |
+
if (typeof arg2 === 'number') {
|
| 156 |
+
byteLength = arg2;
|
| 157 |
+
if (!Number.isSafeInteger(byteLength)) {
|
| 158 |
+
throw new RangeError("'byteLength' must be an integer.");
|
| 159 |
+
}
|
| 160 |
+
if (byteLength <= 0 || byteOffset + byteLength > buffer.byteLength) {
|
| 161 |
+
throw new RangeError(`'byteLength' is out of range (0, ${buffer.byteLength - byteOffset}].`);
|
| 162 |
+
}
|
| 163 |
+
if (typeof arg3 === 'object' && arg3 !== null) {
|
| 164 |
+
options = arg3;
|
| 165 |
+
}
|
| 166 |
+
else if (typeof arg3 !== 'undefined') {
|
| 167 |
+
throw new TypeError("'options' must be an object.");
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
else if (typeof arg2 !== 'undefined') {
|
| 171 |
+
throw new TypeError("'byteLength' must be a number.");
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
else if (typeof arg1 !== 'undefined') {
|
| 175 |
+
throw new TypeError("'options' must be an object.");
|
| 176 |
+
}
|
| 177 |
+
filePathOrUint8Array = new Uint8Array(buffer, byteOffset, byteLength);
|
| 178 |
+
}
|
| 179 |
+
else {
|
| 180 |
+
throw new TypeError("Unexpected argument[0]: must be 'path' or 'buffer'.");
|
| 181 |
+
}
|
| 182 |
+
// resolve backend, update session options with validated EPs, and create session handler
|
| 183 |
+
const [backend, optionsWithValidatedEPs] = await resolveBackendAndExecutionProviders(options);
|
| 184 |
+
const handler = await backend.createInferenceSessionHandler(filePathOrUint8Array, optionsWithValidatedEPs);
|
| 185 |
+
TRACE_EVENT_END('InferenceSession.create');
|
| 186 |
+
TRACE_FUNC_END();
|
| 187 |
+
return new InferenceSession(handler);
|
| 188 |
+
}
|
| 189 |
+
startProfiling() {
|
| 190 |
+
this.handler.startProfiling();
|
| 191 |
+
}
|
| 192 |
+
endProfiling() {
|
| 193 |
+
this.handler.endProfiling();
|
| 194 |
+
}
|
| 195 |
+
get inputNames() {
|
| 196 |
+
return this.handler.inputNames;
|
| 197 |
+
}
|
| 198 |
+
get outputNames() {
|
| 199 |
+
return this.handler.outputNames;
|
| 200 |
+
}
|
| 201 |
+
get inputMetadata() {
|
| 202 |
+
return this.handler.inputMetadata;
|
| 203 |
+
}
|
| 204 |
+
get outputMetadata() {
|
| 205 |
+
return this.handler.outputMetadata;
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
//# sourceMappingURL=inference-session-impl.js.map
|
runtime/vendor/onnxruntime-common/inference-session.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { InferenceSession as InferenceSessionImpl } from './inference-session-impl.js';
|
| 4 |
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
| 5 |
+
export const InferenceSession = InferenceSessionImpl;
|
| 6 |
+
//# sourceMappingURL=inference-session.js.map
|
runtime/vendor/onnxruntime-common/onnx-model.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=onnx-model.js.map
|
runtime/vendor/onnxruntime-common/onnx-value.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=onnx-value.js.map
|
runtime/vendor/onnxruntime-common/tensor-conversion-impl.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
/**
|
| 4 |
+
* implementation of Tensor.toDataURL()
|
| 5 |
+
*/
|
| 6 |
+
export const tensorToDataURL = (tensor, options) => {
|
| 7 |
+
const canvas = typeof document !== 'undefined' ? document.createElement('canvas') : new OffscreenCanvas(1, 1);
|
| 8 |
+
canvas.width = tensor.dims[3];
|
| 9 |
+
canvas.height = tensor.dims[2];
|
| 10 |
+
const pixels2DContext = canvas.getContext('2d');
|
| 11 |
+
if (pixels2DContext != null) {
|
| 12 |
+
// Default values for height and width & format
|
| 13 |
+
let width;
|
| 14 |
+
let height;
|
| 15 |
+
if (options?.tensorLayout !== undefined && options.tensorLayout === 'NHWC') {
|
| 16 |
+
width = tensor.dims[2];
|
| 17 |
+
height = tensor.dims[3];
|
| 18 |
+
}
|
| 19 |
+
else {
|
| 20 |
+
// Default layout is NCWH
|
| 21 |
+
width = tensor.dims[3];
|
| 22 |
+
height = tensor.dims[2];
|
| 23 |
+
}
|
| 24 |
+
const inputformat = options?.format !== undefined ? options.format : 'RGB';
|
| 25 |
+
const norm = options?.norm;
|
| 26 |
+
let normMean;
|
| 27 |
+
let normBias;
|
| 28 |
+
if (norm === undefined || norm.mean === undefined) {
|
| 29 |
+
normMean = [255, 255, 255, 255];
|
| 30 |
+
}
|
| 31 |
+
else {
|
| 32 |
+
if (typeof norm.mean === 'number') {
|
| 33 |
+
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
|
| 34 |
+
}
|
| 35 |
+
else {
|
| 36 |
+
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 0];
|
| 37 |
+
if (norm.mean[3] !== undefined) {
|
| 38 |
+
normMean[3] = norm.mean[3];
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
if (norm === undefined || norm.bias === undefined) {
|
| 43 |
+
normBias = [0, 0, 0, 0];
|
| 44 |
+
}
|
| 45 |
+
else {
|
| 46 |
+
if (typeof norm.bias === 'number') {
|
| 47 |
+
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
|
| 48 |
+
}
|
| 49 |
+
else {
|
| 50 |
+
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0];
|
| 51 |
+
if (norm.bias[3] !== undefined) {
|
| 52 |
+
normBias[3] = norm.bias[3];
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
const stride = height * width;
|
| 57 |
+
// Default pointer assignments
|
| 58 |
+
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
|
| 59 |
+
// Updating the pointer assignments based on the input image format
|
| 60 |
+
if (inputformat === 'RGBA') {
|
| 61 |
+
rTensorPointer = 0;
|
| 62 |
+
gTensorPointer = stride;
|
| 63 |
+
bTensorPointer = stride * 2;
|
| 64 |
+
aTensorPointer = stride * 3;
|
| 65 |
+
}
|
| 66 |
+
else if (inputformat === 'RGB') {
|
| 67 |
+
rTensorPointer = 0;
|
| 68 |
+
gTensorPointer = stride;
|
| 69 |
+
bTensorPointer = stride * 2;
|
| 70 |
+
}
|
| 71 |
+
else if (inputformat === 'RBG') {
|
| 72 |
+
rTensorPointer = 0;
|
| 73 |
+
bTensorPointer = stride;
|
| 74 |
+
gTensorPointer = stride * 2;
|
| 75 |
+
}
|
| 76 |
+
for (let i = 0; i < height; i++) {
|
| 77 |
+
for (let j = 0; j < width; j++) {
|
| 78 |
+
const R = (tensor.data[rTensorPointer++] - normBias[0]) * normMean[0]; // R value
|
| 79 |
+
const G = (tensor.data[gTensorPointer++] - normBias[1]) * normMean[1]; // G value
|
| 80 |
+
const B = (tensor.data[bTensorPointer++] - normBias[2]) * normMean[2]; // B value
|
| 81 |
+
const A = aTensorPointer === -1 ? 255 : (tensor.data[aTensorPointer++] - normBias[3]) * normMean[3]; // A value
|
| 82 |
+
pixels2DContext.fillStyle = 'rgba(' + R + ',' + G + ',' + B + ',' + A + ')';
|
| 83 |
+
pixels2DContext.fillRect(j, i, 1, 1);
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
if ('toDataURL' in canvas) {
|
| 87 |
+
return canvas.toDataURL();
|
| 88 |
+
}
|
| 89 |
+
else {
|
| 90 |
+
throw new Error('toDataURL is not supported');
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
else {
|
| 94 |
+
throw new Error('Can not access image data');
|
| 95 |
+
}
|
| 96 |
+
};
|
| 97 |
+
/**
|
| 98 |
+
* implementation of Tensor.toImageData()
|
| 99 |
+
*/
|
| 100 |
+
export const tensorToImageData = (tensor, options) => {
|
| 101 |
+
const pixels2DContext = typeof document !== 'undefined'
|
| 102 |
+
? document.createElement('canvas').getContext('2d')
|
| 103 |
+
: new OffscreenCanvas(1, 1).getContext('2d');
|
| 104 |
+
let image;
|
| 105 |
+
if (pixels2DContext != null) {
|
| 106 |
+
// Default values for height and width & format
|
| 107 |
+
let width;
|
| 108 |
+
let height;
|
| 109 |
+
let channels;
|
| 110 |
+
if (options?.tensorLayout !== undefined && options.tensorLayout === 'NHWC') {
|
| 111 |
+
width = tensor.dims[2];
|
| 112 |
+
height = tensor.dims[1];
|
| 113 |
+
channels = tensor.dims[3];
|
| 114 |
+
}
|
| 115 |
+
else {
|
| 116 |
+
// Default layout is NCWH
|
| 117 |
+
width = tensor.dims[3];
|
| 118 |
+
height = tensor.dims[2];
|
| 119 |
+
channels = tensor.dims[1];
|
| 120 |
+
}
|
| 121 |
+
const inputformat = options !== undefined ? (options.format !== undefined ? options.format : 'RGB') : 'RGB';
|
| 122 |
+
const norm = options?.norm;
|
| 123 |
+
let normMean;
|
| 124 |
+
let normBias;
|
| 125 |
+
if (norm === undefined || norm.mean === undefined) {
|
| 126 |
+
normMean = [255, 255, 255, 255];
|
| 127 |
+
}
|
| 128 |
+
else {
|
| 129 |
+
if (typeof norm.mean === 'number') {
|
| 130 |
+
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
|
| 131 |
+
}
|
| 132 |
+
else {
|
| 133 |
+
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 255];
|
| 134 |
+
if (norm.mean[3] !== undefined) {
|
| 135 |
+
normMean[3] = norm.mean[3];
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
if (norm === undefined || norm.bias === undefined) {
|
| 140 |
+
normBias = [0, 0, 0, 0];
|
| 141 |
+
}
|
| 142 |
+
else {
|
| 143 |
+
if (typeof norm.bias === 'number') {
|
| 144 |
+
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
|
| 145 |
+
}
|
| 146 |
+
else {
|
| 147 |
+
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0];
|
| 148 |
+
if (norm.bias[3] !== undefined) {
|
| 149 |
+
normBias[3] = norm.bias[3];
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
const stride = height * width;
|
| 154 |
+
if (options !== undefined) {
|
| 155 |
+
if ((options.format !== undefined && channels === 4 && options.format !== 'RGBA') ||
|
| 156 |
+
(channels === 3 && options.format !== 'RGB' && options.format !== 'BGR')) {
|
| 157 |
+
throw new Error("Tensor format doesn't match input tensor dims");
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
// Default pointer assignments
|
| 161 |
+
const step = 4;
|
| 162 |
+
let rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3;
|
| 163 |
+
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
|
| 164 |
+
// Updating the pointer assignments based on the input image format
|
| 165 |
+
if (inputformat === 'RGBA') {
|
| 166 |
+
rTensorPointer = 0;
|
| 167 |
+
gTensorPointer = stride;
|
| 168 |
+
bTensorPointer = stride * 2;
|
| 169 |
+
aTensorPointer = stride * 3;
|
| 170 |
+
}
|
| 171 |
+
else if (inputformat === 'RGB') {
|
| 172 |
+
rTensorPointer = 0;
|
| 173 |
+
gTensorPointer = stride;
|
| 174 |
+
bTensorPointer = stride * 2;
|
| 175 |
+
}
|
| 176 |
+
else if (inputformat === 'RBG') {
|
| 177 |
+
rTensorPointer = 0;
|
| 178 |
+
bTensorPointer = stride;
|
| 179 |
+
gTensorPointer = stride * 2;
|
| 180 |
+
}
|
| 181 |
+
image = pixels2DContext.createImageData(width, height);
|
| 182 |
+
for (let i = 0; i < height * width; rImagePointer += step, gImagePointer += step, bImagePointer += step, aImagePointer += step, i++) {
|
| 183 |
+
image.data[rImagePointer] = (tensor.data[rTensorPointer++] - normBias[0]) * normMean[0]; // R value
|
| 184 |
+
image.data[gImagePointer] = (tensor.data[gTensorPointer++] - normBias[1]) * normMean[1]; // G value
|
| 185 |
+
image.data[bImagePointer] = (tensor.data[bTensorPointer++] - normBias[2]) * normMean[2]; // B value
|
| 186 |
+
image.data[aImagePointer] =
|
| 187 |
+
aTensorPointer === -1 ? 255 : (tensor.data[aTensorPointer++] - normBias[3]) * normMean[3]; // A value
|
| 188 |
+
}
|
| 189 |
+
}
|
| 190 |
+
else {
|
| 191 |
+
throw new Error('Can not access image data');
|
| 192 |
+
}
|
| 193 |
+
return image;
|
| 194 |
+
};
|
| 195 |
+
//# sourceMappingURL=tensor-conversion-impl.js.map
|
runtime/vendor/onnxruntime-common/tensor-conversion.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=tensor-conversion.js.map
|
runtime/vendor/onnxruntime-common/tensor-factory-impl.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { Tensor } from './tensor-impl.js';
|
| 4 |
+
/**
|
| 5 |
+
* Create a new tensor object from image object
|
| 6 |
+
*
|
| 7 |
+
* @param buffer - Extracted image buffer data - assuming RGBA format
|
| 8 |
+
* @param imageFormat - input image configuration - required configurations height, width, format
|
| 9 |
+
* @param tensorFormat - output tensor configuration - Default is RGB format
|
| 10 |
+
*/
|
| 11 |
+
export const bufferToTensor = (buffer, options) => {
|
| 12 |
+
if (buffer === undefined) {
|
| 13 |
+
throw new Error('Image buffer must be defined');
|
| 14 |
+
}
|
| 15 |
+
if (options.height === undefined || options.width === undefined) {
|
| 16 |
+
throw new Error('Image height and width must be defined');
|
| 17 |
+
}
|
| 18 |
+
if (options.tensorLayout === 'NHWC') {
|
| 19 |
+
throw new Error('NHWC Tensor layout is not supported yet');
|
| 20 |
+
}
|
| 21 |
+
const { height, width } = options;
|
| 22 |
+
const norm = options.norm ?? { mean: 255, bias: 0 };
|
| 23 |
+
let normMean;
|
| 24 |
+
let normBias;
|
| 25 |
+
if (typeof norm.mean === 'number') {
|
| 26 |
+
normMean = [norm.mean, norm.mean, norm.mean, norm.mean];
|
| 27 |
+
}
|
| 28 |
+
else {
|
| 29 |
+
normMean = [norm.mean[0], norm.mean[1], norm.mean[2], norm.mean[3] ?? 255];
|
| 30 |
+
}
|
| 31 |
+
if (typeof norm.bias === 'number') {
|
| 32 |
+
normBias = [norm.bias, norm.bias, norm.bias, norm.bias];
|
| 33 |
+
}
|
| 34 |
+
else {
|
| 35 |
+
normBias = [norm.bias[0], norm.bias[1], norm.bias[2], norm.bias[3] ?? 0];
|
| 36 |
+
}
|
| 37 |
+
const inputformat = options.format !== undefined ? options.format : 'RGBA';
|
| 38 |
+
// default value is RGBA since imagedata and HTMLImageElement uses it
|
| 39 |
+
const outputformat = options.tensorFormat !== undefined ? (options.tensorFormat !== undefined ? options.tensorFormat : 'RGB') : 'RGB';
|
| 40 |
+
const stride = height * width;
|
| 41 |
+
const float32Data = outputformat === 'RGBA' ? new Float32Array(stride * 4) : new Float32Array(stride * 3);
|
| 42 |
+
// Default pointer assignments
|
| 43 |
+
let step = 4, rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3;
|
| 44 |
+
let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1;
|
| 45 |
+
// Updating the pointer assignments based on the input image format
|
| 46 |
+
if (inputformat === 'RGB') {
|
| 47 |
+
step = 3;
|
| 48 |
+
rImagePointer = 0;
|
| 49 |
+
gImagePointer = 1;
|
| 50 |
+
bImagePointer = 2;
|
| 51 |
+
aImagePointer = -1;
|
| 52 |
+
}
|
| 53 |
+
// Updating the pointer assignments based on the output tensor format
|
| 54 |
+
if (outputformat === 'RGBA') {
|
| 55 |
+
aTensorPointer = stride * 3;
|
| 56 |
+
}
|
| 57 |
+
else if (outputformat === 'RBG') {
|
| 58 |
+
rTensorPointer = 0;
|
| 59 |
+
bTensorPointer = stride;
|
| 60 |
+
gTensorPointer = stride * 2;
|
| 61 |
+
}
|
| 62 |
+
else if (outputformat === 'BGR') {
|
| 63 |
+
bTensorPointer = 0;
|
| 64 |
+
gTensorPointer = stride;
|
| 65 |
+
rTensorPointer = stride * 2;
|
| 66 |
+
}
|
| 67 |
+
for (let i = 0; i < stride; i++, rImagePointer += step, bImagePointer += step, gImagePointer += step, aImagePointer += step) {
|
| 68 |
+
float32Data[rTensorPointer++] = (buffer[rImagePointer] + normBias[0]) / normMean[0];
|
| 69 |
+
float32Data[gTensorPointer++] = (buffer[gImagePointer] + normBias[1]) / normMean[1];
|
| 70 |
+
float32Data[bTensorPointer++] = (buffer[bImagePointer] + normBias[2]) / normMean[2];
|
| 71 |
+
if (aTensorPointer !== -1 && aImagePointer !== -1) {
|
| 72 |
+
float32Data[aTensorPointer++] = (buffer[aImagePointer] + normBias[3]) / normMean[3];
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
// Float32Array -> ort.Tensor
|
| 76 |
+
const outputTensor = outputformat === 'RGBA'
|
| 77 |
+
? new Tensor('float32', float32Data, [1, 4, height, width])
|
| 78 |
+
: new Tensor('float32', float32Data, [1, 3, height, width]);
|
| 79 |
+
return outputTensor;
|
| 80 |
+
};
|
| 81 |
+
/**
|
| 82 |
+
* implementation of Tensor.fromImage().
|
| 83 |
+
*/
|
| 84 |
+
export const tensorFromImage = async (image, options) => {
|
| 85 |
+
// checking the type of image object
|
| 86 |
+
const isHTMLImageEle = typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement;
|
| 87 |
+
const isImageDataEle = typeof ImageData !== 'undefined' && image instanceof ImageData;
|
| 88 |
+
const isImageBitmap = typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap;
|
| 89 |
+
const isString = typeof image === 'string';
|
| 90 |
+
let data;
|
| 91 |
+
let bufferToTensorOptions = options ?? {};
|
| 92 |
+
const createCanvas = () => {
|
| 93 |
+
if (typeof document !== 'undefined') {
|
| 94 |
+
return document.createElement('canvas');
|
| 95 |
+
}
|
| 96 |
+
else if (typeof OffscreenCanvas !== 'undefined') {
|
| 97 |
+
return new OffscreenCanvas(1, 1);
|
| 98 |
+
}
|
| 99 |
+
else {
|
| 100 |
+
throw new Error('Canvas is not supported');
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
const createCanvasContext = (canvas) => {
|
| 104 |
+
if (typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement) {
|
| 105 |
+
return canvas.getContext('2d');
|
| 106 |
+
}
|
| 107 |
+
else if (canvas instanceof OffscreenCanvas) {
|
| 108 |
+
return canvas.getContext('2d');
|
| 109 |
+
}
|
| 110 |
+
else {
|
| 111 |
+
return null;
|
| 112 |
+
}
|
| 113 |
+
};
|
| 114 |
+
// filling and checking image configuration options
|
| 115 |
+
if (isHTMLImageEle) {
|
| 116 |
+
// HTMLImageElement - image object - format is RGBA by default
|
| 117 |
+
const canvas = createCanvas();
|
| 118 |
+
canvas.width = image.width;
|
| 119 |
+
canvas.height = image.height;
|
| 120 |
+
const pixels2DContext = createCanvasContext(canvas);
|
| 121 |
+
if (pixels2DContext != null) {
|
| 122 |
+
let height = image.height;
|
| 123 |
+
let width = image.width;
|
| 124 |
+
if (options !== undefined && options.resizedHeight !== undefined && options.resizedWidth !== undefined) {
|
| 125 |
+
height = options.resizedHeight;
|
| 126 |
+
width = options.resizedWidth;
|
| 127 |
+
}
|
| 128 |
+
if (options !== undefined) {
|
| 129 |
+
bufferToTensorOptions = options;
|
| 130 |
+
if (options.tensorFormat !== undefined) {
|
| 131 |
+
throw new Error('Image input config format must be RGBA for HTMLImageElement');
|
| 132 |
+
}
|
| 133 |
+
else {
|
| 134 |
+
bufferToTensorOptions.tensorFormat = 'RGBA';
|
| 135 |
+
}
|
| 136 |
+
bufferToTensorOptions.height = height;
|
| 137 |
+
bufferToTensorOptions.width = width;
|
| 138 |
+
}
|
| 139 |
+
else {
|
| 140 |
+
bufferToTensorOptions.tensorFormat = 'RGBA';
|
| 141 |
+
bufferToTensorOptions.height = height;
|
| 142 |
+
bufferToTensorOptions.width = width;
|
| 143 |
+
}
|
| 144 |
+
pixels2DContext.drawImage(image, 0, 0);
|
| 145 |
+
data = pixels2DContext.getImageData(0, 0, width, height).data;
|
| 146 |
+
}
|
| 147 |
+
else {
|
| 148 |
+
throw new Error('Can not access image data');
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
else if (isImageDataEle) {
|
| 152 |
+
let height;
|
| 153 |
+
let width;
|
| 154 |
+
if (options !== undefined && options.resizedWidth !== undefined && options.resizedHeight !== undefined) {
|
| 155 |
+
height = options.resizedHeight;
|
| 156 |
+
width = options.resizedWidth;
|
| 157 |
+
}
|
| 158 |
+
else {
|
| 159 |
+
height = image.height;
|
| 160 |
+
width = image.width;
|
| 161 |
+
}
|
| 162 |
+
if (options !== undefined) {
|
| 163 |
+
bufferToTensorOptions = options;
|
| 164 |
+
}
|
| 165 |
+
bufferToTensorOptions.format = 'RGBA';
|
| 166 |
+
bufferToTensorOptions.height = height;
|
| 167 |
+
bufferToTensorOptions.width = width;
|
| 168 |
+
if (options !== undefined) {
|
| 169 |
+
const tempCanvas = createCanvas();
|
| 170 |
+
tempCanvas.width = width;
|
| 171 |
+
tempCanvas.height = height;
|
| 172 |
+
const pixels2DContext = createCanvasContext(tempCanvas);
|
| 173 |
+
if (pixels2DContext != null) {
|
| 174 |
+
pixels2DContext.putImageData(image, 0, 0);
|
| 175 |
+
data = pixels2DContext.getImageData(0, 0, width, height).data;
|
| 176 |
+
}
|
| 177 |
+
else {
|
| 178 |
+
throw new Error('Can not access image data');
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
else {
|
| 182 |
+
data = image.data;
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
else if (isImageBitmap) {
|
| 186 |
+
// ImageBitmap - image object - format must be provided by user
|
| 187 |
+
if (options === undefined) {
|
| 188 |
+
throw new Error('Please provide image config with format for Imagebitmap');
|
| 189 |
+
}
|
| 190 |
+
const canvas = createCanvas();
|
| 191 |
+
canvas.width = image.width;
|
| 192 |
+
canvas.height = image.height;
|
| 193 |
+
const pixels2DContext = createCanvasContext(canvas);
|
| 194 |
+
if (pixels2DContext != null) {
|
| 195 |
+
const height = image.height;
|
| 196 |
+
const width = image.width;
|
| 197 |
+
pixels2DContext.drawImage(image, 0, 0, width, height);
|
| 198 |
+
data = pixels2DContext.getImageData(0, 0, width, height).data;
|
| 199 |
+
bufferToTensorOptions.height = height;
|
| 200 |
+
bufferToTensorOptions.width = width;
|
| 201 |
+
return bufferToTensor(data, bufferToTensorOptions);
|
| 202 |
+
}
|
| 203 |
+
else {
|
| 204 |
+
throw new Error('Can not access image data');
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
else if (isString) {
|
| 208 |
+
return new Promise((resolve, reject) => {
|
| 209 |
+
const canvas = createCanvas();
|
| 210 |
+
const context = createCanvasContext(canvas);
|
| 211 |
+
if (!image || !context) {
|
| 212 |
+
return reject();
|
| 213 |
+
}
|
| 214 |
+
const newImage = new Image();
|
| 215 |
+
newImage.crossOrigin = 'Anonymous';
|
| 216 |
+
newImage.src = image;
|
| 217 |
+
newImage.onload = () => {
|
| 218 |
+
canvas.width = newImage.width;
|
| 219 |
+
canvas.height = newImage.height;
|
| 220 |
+
context.drawImage(newImage, 0, 0, canvas.width, canvas.height);
|
| 221 |
+
const img = context.getImageData(0, 0, canvas.width, canvas.height);
|
| 222 |
+
bufferToTensorOptions.height = canvas.height;
|
| 223 |
+
bufferToTensorOptions.width = canvas.width;
|
| 224 |
+
resolve(bufferToTensor(img.data, bufferToTensorOptions));
|
| 225 |
+
};
|
| 226 |
+
});
|
| 227 |
+
}
|
| 228 |
+
else {
|
| 229 |
+
throw new Error('Input data provided is not supported - aborted tensor creation');
|
| 230 |
+
}
|
| 231 |
+
if (data !== undefined) {
|
| 232 |
+
return bufferToTensor(data, bufferToTensorOptions);
|
| 233 |
+
}
|
| 234 |
+
else {
|
| 235 |
+
throw new Error('Input data provided is not supported - aborted tensor creation');
|
| 236 |
+
}
|
| 237 |
+
};
|
| 238 |
+
/**
|
| 239 |
+
* implementation of Tensor.fromTexture().
|
| 240 |
+
*/
|
| 241 |
+
export const tensorFromTexture = (texture, options) => {
|
| 242 |
+
const { width, height, download, dispose } = options;
|
| 243 |
+
// Always assume RGBAF32. TODO: support different texture format
|
| 244 |
+
const dims = [1, height, width, 4];
|
| 245 |
+
return new Tensor({ location: 'texture', type: 'float32', texture, dims, download, dispose });
|
| 246 |
+
};
|
| 247 |
+
/**
|
| 248 |
+
* implementation of Tensor.fromGpuBuffer().
|
| 249 |
+
*/
|
| 250 |
+
export const tensorFromGpuBuffer = (gpuBuffer, options) => {
|
| 251 |
+
const { dataType, dims, download, dispose } = options;
|
| 252 |
+
return new Tensor({ location: 'gpu-buffer', type: dataType ?? 'float32', gpuBuffer, dims, download, dispose });
|
| 253 |
+
};
|
| 254 |
+
/**
|
| 255 |
+
* implementation of Tensor.fromMLTensor().
|
| 256 |
+
*/
|
| 257 |
+
export const tensorFromMLTensor = (mlTensor, options) => {
|
| 258 |
+
const { dataType, dims, download, dispose } = options;
|
| 259 |
+
return new Tensor({ location: 'ml-tensor', type: dataType ?? 'float32', mlTensor, dims, download, dispose });
|
| 260 |
+
};
|
| 261 |
+
/**
|
| 262 |
+
* implementation of Tensor.fromPinnedBuffer().
|
| 263 |
+
*/
|
| 264 |
+
export const tensorFromPinnedBuffer = (type, buffer, dims) => new Tensor({ location: 'cpu-pinned', type, data: buffer, dims: dims ?? [buffer.length] });
|
| 265 |
+
//# sourceMappingURL=tensor-factory-impl.js.map
|
runtime/vendor/onnxruntime-common/tensor-factory.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=tensor-factory.js.map
|
runtime/vendor/onnxruntime-common/tensor-impl-type-mapping.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap.
|
| 4 |
+
export const NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP = new Map([
|
| 5 |
+
['float32', Float32Array],
|
| 6 |
+
['uint8', Uint8Array],
|
| 7 |
+
['int8', Int8Array],
|
| 8 |
+
['uint16', Uint16Array],
|
| 9 |
+
['int16', Int16Array],
|
| 10 |
+
['int32', Int32Array],
|
| 11 |
+
['bool', Uint8Array],
|
| 12 |
+
['float64', Float64Array],
|
| 13 |
+
['uint32', Uint32Array],
|
| 14 |
+
['int4', Uint8Array],
|
| 15 |
+
['uint4', Uint8Array],
|
| 16 |
+
]);
|
| 17 |
+
// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap.
|
| 18 |
+
export const NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP = new Map([
|
| 19 |
+
[Float32Array, 'float32'],
|
| 20 |
+
[Uint8Array, 'uint8'],
|
| 21 |
+
[Int8Array, 'int8'],
|
| 22 |
+
[Uint16Array, 'uint16'],
|
| 23 |
+
[Int16Array, 'int16'],
|
| 24 |
+
[Int32Array, 'int32'],
|
| 25 |
+
[Float64Array, 'float64'],
|
| 26 |
+
[Uint32Array, 'uint32'],
|
| 27 |
+
]);
|
| 28 |
+
// the following code allows delaying execution of BigInt/Float16Array checking. This allows lazy initialization for
|
| 29 |
+
// NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP and NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, which allows BigInt/Float16Array
|
| 30 |
+
// polyfill if available.
|
| 31 |
+
let isTypedArrayChecked = false;
|
| 32 |
+
export const checkTypedArray = () => {
|
| 33 |
+
if (!isTypedArrayChecked) {
|
| 34 |
+
isTypedArrayChecked = true;
|
| 35 |
+
const isBigInt64ArrayAvailable = typeof BigInt64Array !== 'undefined' && BigInt64Array.from;
|
| 36 |
+
const isBigUint64ArrayAvailable = typeof BigUint64Array !== 'undefined' && BigUint64Array.from;
|
| 37 |
+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any
|
| 38 |
+
const Float16Array = globalThis.Float16Array;
|
| 39 |
+
const isFloat16ArrayAvailable = typeof Float16Array !== 'undefined' && Float16Array.from;
|
| 40 |
+
if (isBigInt64ArrayAvailable) {
|
| 41 |
+
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('int64', BigInt64Array);
|
| 42 |
+
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigInt64Array, 'int64');
|
| 43 |
+
}
|
| 44 |
+
if (isBigUint64ArrayAvailable) {
|
| 45 |
+
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('uint64', BigUint64Array);
|
| 46 |
+
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigUint64Array, 'uint64');
|
| 47 |
+
}
|
| 48 |
+
if (isFloat16ArrayAvailable) {
|
| 49 |
+
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('float16', Float16Array);
|
| 50 |
+
NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(Float16Array, 'float16');
|
| 51 |
+
}
|
| 52 |
+
else {
|
| 53 |
+
// if Float16Array is not available, use 'Uint16Array' to store the data.
|
| 54 |
+
NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('float16', Uint16Array);
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
};
|
| 58 |
+
//# sourceMappingURL=tensor-impl-type-mapping.js.map
|
runtime/vendor/onnxruntime-common/tensor-impl.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { tensorToDataURL, tensorToImageData } from './tensor-conversion-impl.js';
|
| 4 |
+
import { tensorFromGpuBuffer, tensorFromImage, tensorFromMLTensor, tensorFromPinnedBuffer, tensorFromTexture, } from './tensor-factory-impl.js';
|
| 5 |
+
import { checkTypedArray, NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP, NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, } from './tensor-impl-type-mapping.js';
|
| 6 |
+
import { calculateSize, tensorReshape } from './tensor-utils-impl.js';
|
| 7 |
+
/**
|
| 8 |
+
* the implementation of Tensor interface.
|
| 9 |
+
*
|
| 10 |
+
* @ignore
|
| 11 |
+
*/
|
| 12 |
+
export class Tensor {
|
| 13 |
+
/**
|
| 14 |
+
* implementation.
|
| 15 |
+
*/
|
| 16 |
+
constructor(arg0, arg1, arg2) {
|
| 17 |
+
// perform one-time check for BigInt/Float16Array support
|
| 18 |
+
checkTypedArray();
|
| 19 |
+
let type;
|
| 20 |
+
let dims;
|
| 21 |
+
if (typeof arg0 === 'object' && 'location' in arg0) {
|
| 22 |
+
//
|
| 23 |
+
// constructing tensor from specific location
|
| 24 |
+
//
|
| 25 |
+
this.dataLocation = arg0.location;
|
| 26 |
+
type = arg0.type;
|
| 27 |
+
dims = arg0.dims;
|
| 28 |
+
switch (arg0.location) {
|
| 29 |
+
case 'cpu-pinned': {
|
| 30 |
+
const expectedTypedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(type);
|
| 31 |
+
if (!expectedTypedArrayConstructor) {
|
| 32 |
+
throw new TypeError(`unsupported type "${type}" to create tensor from pinned buffer`);
|
| 33 |
+
}
|
| 34 |
+
if (!(arg0.data instanceof expectedTypedArrayConstructor)) {
|
| 35 |
+
throw new TypeError(`buffer should be of type ${expectedTypedArrayConstructor.name}`);
|
| 36 |
+
}
|
| 37 |
+
this.cpuData = arg0.data;
|
| 38 |
+
break;
|
| 39 |
+
}
|
| 40 |
+
case 'texture': {
|
| 41 |
+
if (type !== 'float32') {
|
| 42 |
+
throw new TypeError(`unsupported type "${type}" to create tensor from texture`);
|
| 43 |
+
}
|
| 44 |
+
this.gpuTextureData = arg0.texture;
|
| 45 |
+
this.downloader = arg0.download;
|
| 46 |
+
this.disposer = arg0.dispose;
|
| 47 |
+
break;
|
| 48 |
+
}
|
| 49 |
+
case 'gpu-buffer': {
|
| 50 |
+
if (type !== 'float32' &&
|
| 51 |
+
type !== 'float16' &&
|
| 52 |
+
type !== 'int32' &&
|
| 53 |
+
type !== 'int64' &&
|
| 54 |
+
type !== 'uint32' &&
|
| 55 |
+
type !== 'uint8' &&
|
| 56 |
+
type !== 'bool' &&
|
| 57 |
+
type !== 'uint4' &&
|
| 58 |
+
type !== 'int4') {
|
| 59 |
+
throw new TypeError(`unsupported type "${type}" to create tensor from gpu buffer`);
|
| 60 |
+
}
|
| 61 |
+
this.gpuBufferData = arg0.gpuBuffer;
|
| 62 |
+
this.downloader = arg0.download;
|
| 63 |
+
this.disposer = arg0.dispose;
|
| 64 |
+
break;
|
| 65 |
+
}
|
| 66 |
+
case 'ml-tensor': {
|
| 67 |
+
if (type !== 'float32' &&
|
| 68 |
+
type !== 'float16' &&
|
| 69 |
+
type !== 'int32' &&
|
| 70 |
+
type !== 'int64' &&
|
| 71 |
+
type !== 'uint32' &&
|
| 72 |
+
type !== 'uint64' &&
|
| 73 |
+
type !== 'int8' &&
|
| 74 |
+
type !== 'uint8' &&
|
| 75 |
+
type !== 'bool' &&
|
| 76 |
+
type !== 'uint4' &&
|
| 77 |
+
type !== 'int4') {
|
| 78 |
+
throw new TypeError(`unsupported type "${type}" to create tensor from MLTensor`);
|
| 79 |
+
}
|
| 80 |
+
this.mlTensorData = arg0.mlTensor;
|
| 81 |
+
this.downloader = arg0.download;
|
| 82 |
+
this.disposer = arg0.dispose;
|
| 83 |
+
break;
|
| 84 |
+
}
|
| 85 |
+
default:
|
| 86 |
+
throw new Error(`Tensor constructor: unsupported location '${this.dataLocation}'`);
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
else {
|
| 90 |
+
//
|
| 91 |
+
// constructing tensor of location 'cpu'
|
| 92 |
+
//
|
| 93 |
+
let data;
|
| 94 |
+
let maybeDims;
|
| 95 |
+
// check whether arg0 is type or data
|
| 96 |
+
if (typeof arg0 === 'string') {
|
| 97 |
+
//
|
| 98 |
+
// Override: constructor(type, data, ...)
|
| 99 |
+
//
|
| 100 |
+
type = arg0;
|
| 101 |
+
maybeDims = arg2;
|
| 102 |
+
if (arg0 === 'string') {
|
| 103 |
+
// string tensor
|
| 104 |
+
if (!Array.isArray(arg1)) {
|
| 105 |
+
throw new TypeError("A string tensor's data must be a string array.");
|
| 106 |
+
}
|
| 107 |
+
// we don't check whether every element in the array is string; this is too slow. we assume it's correct and
|
| 108 |
+
// error will be populated at inference
|
| 109 |
+
data = arg1;
|
| 110 |
+
}
|
| 111 |
+
else {
|
| 112 |
+
// numeric tensor
|
| 113 |
+
const typedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(arg0);
|
| 114 |
+
if (typedArrayConstructor === undefined) {
|
| 115 |
+
throw new TypeError(`Unsupported tensor type: ${arg0}.`);
|
| 116 |
+
}
|
| 117 |
+
if (Array.isArray(arg1)) {
|
| 118 |
+
if ((arg0 === 'float16' && typedArrayConstructor === Uint16Array) || arg0 === 'uint4' || arg0 === 'int4') {
|
| 119 |
+
// - 'float16':
|
| 120 |
+
// When no Float16Array polyfill is used, we cannot create 'float16' tensor from number array.
|
| 121 |
+
//
|
| 122 |
+
// Throw error here because when user try to use number array as data,
|
| 123 |
+
// e.g. new Tensor('float16', [1, 2, 3, 4], dims)), it will actually call
|
| 124 |
+
// Uint16Array.from(arg1) which generates wrong data.
|
| 125 |
+
//
|
| 126 |
+
// - 'uint4' and 'int4':
|
| 127 |
+
// Uint8Array.from(arg1) will generate wrong data for 'uint4' and 'int4' tensor.
|
| 128 |
+
//
|
| 129 |
+
throw new TypeError(`Creating a ${arg0} tensor from number array is not supported. Please use ${typedArrayConstructor.name} as data.`);
|
| 130 |
+
}
|
| 131 |
+
else if (arg0 === 'uint64' || arg0 === 'int64') {
|
| 132 |
+
// use 'as any' here because:
|
| 133 |
+
// 1. TypeScript's check on type of 'Array.isArray()' does not work with readonly arrays.
|
| 134 |
+
// see https://github.com/microsoft/TypeScript/issues/17002
|
| 135 |
+
// 2. TypeScript's check on union type of '(BigInt64ArrayConstructor|BigUint64ArrayConstructor).from()'
|
| 136 |
+
// does not accept parameter mapFn.
|
| 137 |
+
// 3. parameters of 'SupportedTypedArrayConstructors.from()' does not match the requirement of the union
|
| 138 |
+
// type.
|
| 139 |
+
// assume 'arg1' is of type "readonly number[]|readonly bigint[]" here.
|
| 140 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 141 |
+
data = typedArrayConstructor.from(arg1, BigInt);
|
| 142 |
+
}
|
| 143 |
+
else {
|
| 144 |
+
// assume 'arg1' is of type "readonly number[]" here.
|
| 145 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 146 |
+
data = typedArrayConstructor.from(arg1);
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
else if (arg1 instanceof typedArrayConstructor) {
|
| 150 |
+
data = arg1;
|
| 151 |
+
}
|
| 152 |
+
else if (arg1 instanceof Uint8ClampedArray) {
|
| 153 |
+
if (arg0 === 'uint8') {
|
| 154 |
+
data = Uint8Array.from(arg1);
|
| 155 |
+
}
|
| 156 |
+
else {
|
| 157 |
+
throw new TypeError(`A Uint8ClampedArray tensor's data must be type of uint8`);
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
else if (arg0 === 'float16' && arg1 instanceof Uint16Array && typedArrayConstructor !== Uint16Array) {
|
| 161 |
+
// when Float16Array is available and data is of type Uint16Array.
|
| 162 |
+
// We allow Uint16Array to be passed in as data for 'float16' tensor until Float16Array is generally
|
| 163 |
+
// supported in JavaScript environment.
|
| 164 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 165 |
+
data = new globalThis.Float16Array(arg1.buffer, arg1.byteOffset, arg1.length);
|
| 166 |
+
}
|
| 167 |
+
else {
|
| 168 |
+
throw new TypeError(`A ${type} tensor's data must be type of ${typedArrayConstructor}`);
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
else {
|
| 173 |
+
//
|
| 174 |
+
// Override: constructor(data, ...)
|
| 175 |
+
//
|
| 176 |
+
maybeDims = arg1;
|
| 177 |
+
if (Array.isArray(arg0)) {
|
| 178 |
+
// only boolean[] and string[] is supported
|
| 179 |
+
if (arg0.length === 0) {
|
| 180 |
+
throw new TypeError('Tensor type cannot be inferred from an empty array.');
|
| 181 |
+
}
|
| 182 |
+
const firstElementType = typeof arg0[0];
|
| 183 |
+
if (firstElementType === 'string') {
|
| 184 |
+
type = 'string';
|
| 185 |
+
data = arg0;
|
| 186 |
+
}
|
| 187 |
+
else if (firstElementType === 'boolean') {
|
| 188 |
+
type = 'bool';
|
| 189 |
+
// 'arg0' is of type 'boolean[]'. Uint8Array.from(boolean[]) actually works, but typescript thinks this is
|
| 190 |
+
// wrong type. We use 'as any' to make it happy.
|
| 191 |
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
| 192 |
+
data = Uint8Array.from(arg0);
|
| 193 |
+
}
|
| 194 |
+
else {
|
| 195 |
+
throw new TypeError(`Invalid element type of data array: ${firstElementType}.`);
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
else if (arg0 instanceof Uint8ClampedArray) {
|
| 199 |
+
type = 'uint8';
|
| 200 |
+
data = Uint8Array.from(arg0);
|
| 201 |
+
}
|
| 202 |
+
else {
|
| 203 |
+
// get tensor type from TypedArray
|
| 204 |
+
const mappedType = NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.get(arg0.constructor);
|
| 205 |
+
if (mappedType === undefined) {
|
| 206 |
+
throw new TypeError(`Unsupported type for tensor data: ${arg0.constructor}.`);
|
| 207 |
+
}
|
| 208 |
+
type = mappedType;
|
| 209 |
+
data = arg0;
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
// type and data is processed, now processing dims
|
| 213 |
+
if (maybeDims === undefined) {
|
| 214 |
+
// assume 1-D tensor if dims omitted
|
| 215 |
+
maybeDims = [data.length];
|
| 216 |
+
}
|
| 217 |
+
else if (!Array.isArray(maybeDims)) {
|
| 218 |
+
throw new TypeError("A tensor's dims must be a number array");
|
| 219 |
+
}
|
| 220 |
+
dims = maybeDims;
|
| 221 |
+
this.cpuData = data;
|
| 222 |
+
this.dataLocation = 'cpu';
|
| 223 |
+
}
|
| 224 |
+
// perform check on dims
|
| 225 |
+
const size = calculateSize(dims);
|
| 226 |
+
// if data is on CPU, check whether data length matches tensor size
|
| 227 |
+
if (this.cpuData && size !== this.cpuData.length) {
|
| 228 |
+
if ((type === 'uint4' || type === 'int4') && Math.ceil(size / 2) === this.cpuData.length) {
|
| 229 |
+
// for (u)int4, the data length is half of the tensor size. So we check this special case when size is odd.
|
| 230 |
+
}
|
| 231 |
+
else {
|
| 232 |
+
throw new Error(`Tensor's size(${size}) does not match data length(${this.cpuData.length}).`);
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
this.type = type;
|
| 236 |
+
this.dims = dims;
|
| 237 |
+
this.size = size;
|
| 238 |
+
}
|
| 239 |
+
// #endregion
|
| 240 |
+
// #region factory
|
| 241 |
+
static async fromImage(image, options) {
|
| 242 |
+
return tensorFromImage(image, options);
|
| 243 |
+
}
|
| 244 |
+
static fromTexture(texture, options) {
|
| 245 |
+
return tensorFromTexture(texture, options);
|
| 246 |
+
}
|
| 247 |
+
static fromGpuBuffer(gpuBuffer, options) {
|
| 248 |
+
return tensorFromGpuBuffer(gpuBuffer, options);
|
| 249 |
+
}
|
| 250 |
+
static fromMLTensor(mlTensor, options) {
|
| 251 |
+
return tensorFromMLTensor(mlTensor, options);
|
| 252 |
+
}
|
| 253 |
+
static fromPinnedBuffer(type, buffer, dims) {
|
| 254 |
+
return tensorFromPinnedBuffer(type, buffer, dims);
|
| 255 |
+
}
|
| 256 |
+
// #endregion
|
| 257 |
+
// #region conversions
|
| 258 |
+
toDataURL(options) {
|
| 259 |
+
return tensorToDataURL(this, options);
|
| 260 |
+
}
|
| 261 |
+
toImageData(options) {
|
| 262 |
+
return tensorToImageData(this, options);
|
| 263 |
+
}
|
| 264 |
+
// #endregion
|
| 265 |
+
// #region properties
|
| 266 |
+
get data() {
|
| 267 |
+
this.ensureValid();
|
| 268 |
+
if (!this.cpuData) {
|
| 269 |
+
throw new Error('The data is not on CPU. Use `getData()` to download GPU data to CPU, ' +
|
| 270 |
+
'or use `texture` or `gpuBuffer` property to access the GPU data directly.');
|
| 271 |
+
}
|
| 272 |
+
return this.cpuData;
|
| 273 |
+
}
|
| 274 |
+
get location() {
|
| 275 |
+
return this.dataLocation;
|
| 276 |
+
}
|
| 277 |
+
get texture() {
|
| 278 |
+
this.ensureValid();
|
| 279 |
+
if (!this.gpuTextureData) {
|
| 280 |
+
throw new Error('The data is not stored as a WebGL texture.');
|
| 281 |
+
}
|
| 282 |
+
return this.gpuTextureData;
|
| 283 |
+
}
|
| 284 |
+
get gpuBuffer() {
|
| 285 |
+
this.ensureValid();
|
| 286 |
+
if (!this.gpuBufferData) {
|
| 287 |
+
throw new Error('The data is not stored as a WebGPU buffer.');
|
| 288 |
+
}
|
| 289 |
+
return this.gpuBufferData;
|
| 290 |
+
}
|
| 291 |
+
get mlTensor() {
|
| 292 |
+
this.ensureValid();
|
| 293 |
+
if (!this.mlTensorData) {
|
| 294 |
+
throw new Error('The data is not stored as a WebNN MLTensor.');
|
| 295 |
+
}
|
| 296 |
+
return this.mlTensorData;
|
| 297 |
+
}
|
| 298 |
+
// #endregion
|
| 299 |
+
// #region methods
|
| 300 |
+
async getData(releaseData) {
|
| 301 |
+
this.ensureValid();
|
| 302 |
+
switch (this.dataLocation) {
|
| 303 |
+
case 'cpu':
|
| 304 |
+
case 'cpu-pinned':
|
| 305 |
+
return this.data;
|
| 306 |
+
case 'texture':
|
| 307 |
+
case 'gpu-buffer':
|
| 308 |
+
case 'ml-tensor': {
|
| 309 |
+
if (!this.downloader) {
|
| 310 |
+
throw new Error('The current tensor is not created with a specified data downloader.');
|
| 311 |
+
}
|
| 312 |
+
if (this.isDownloading) {
|
| 313 |
+
throw new Error('The current tensor is being downloaded.');
|
| 314 |
+
}
|
| 315 |
+
try {
|
| 316 |
+
this.isDownloading = true;
|
| 317 |
+
const data = await this.downloader();
|
| 318 |
+
this.downloader = undefined;
|
| 319 |
+
this.dataLocation = 'cpu';
|
| 320 |
+
this.cpuData = data;
|
| 321 |
+
if (releaseData && this.disposer) {
|
| 322 |
+
this.disposer();
|
| 323 |
+
this.disposer = undefined;
|
| 324 |
+
}
|
| 325 |
+
return data;
|
| 326 |
+
}
|
| 327 |
+
finally {
|
| 328 |
+
this.isDownloading = false;
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
default:
|
| 332 |
+
throw new Error(`cannot get data from location: ${this.dataLocation}`);
|
| 333 |
+
}
|
| 334 |
+
}
|
| 335 |
+
dispose() {
|
| 336 |
+
if (this.isDownloading) {
|
| 337 |
+
throw new Error('The current tensor is being downloaded.');
|
| 338 |
+
}
|
| 339 |
+
if (this.disposer) {
|
| 340 |
+
this.disposer();
|
| 341 |
+
this.disposer = undefined;
|
| 342 |
+
}
|
| 343 |
+
this.cpuData = undefined;
|
| 344 |
+
this.gpuTextureData = undefined;
|
| 345 |
+
this.gpuBufferData = undefined;
|
| 346 |
+
this.mlTensorData = undefined;
|
| 347 |
+
this.downloader = undefined;
|
| 348 |
+
this.isDownloading = undefined;
|
| 349 |
+
this.dataLocation = 'none';
|
| 350 |
+
}
|
| 351 |
+
// #endregion
|
| 352 |
+
// #region tensor utilities
|
| 353 |
+
ensureValid() {
|
| 354 |
+
if (this.dataLocation === 'none') {
|
| 355 |
+
throw new Error('The tensor is disposed.');
|
| 356 |
+
}
|
| 357 |
+
}
|
| 358 |
+
reshape(dims) {
|
| 359 |
+
this.ensureValid();
|
| 360 |
+
if (this.downloader || this.disposer) {
|
| 361 |
+
throw new Error('Cannot reshape a tensor that owns GPU resource.');
|
| 362 |
+
}
|
| 363 |
+
return tensorReshape(this, dims);
|
| 364 |
+
}
|
| 365 |
+
}
|
| 366 |
+
//# sourceMappingURL=tensor-impl.js.map
|
runtime/vendor/onnxruntime-common/tensor-utils-impl.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { Tensor } from './tensor-impl.js';
|
| 4 |
+
/**
|
| 5 |
+
* calculate size from dims.
|
| 6 |
+
*
|
| 7 |
+
* @param dims the dims array. May be an illegal input.
|
| 8 |
+
*/
|
| 9 |
+
export const calculateSize = (dims) => {
|
| 10 |
+
let size = 1;
|
| 11 |
+
for (let i = 0; i < dims.length; i++) {
|
| 12 |
+
const dim = dims[i];
|
| 13 |
+
if (typeof dim !== 'number' || !Number.isSafeInteger(dim)) {
|
| 14 |
+
throw new TypeError(`dims[${i}] must be an integer, got: ${dim}`);
|
| 15 |
+
}
|
| 16 |
+
if (dim < 0) {
|
| 17 |
+
throw new RangeError(`dims[${i}] must be a non-negative integer, got: ${dim}`);
|
| 18 |
+
}
|
| 19 |
+
size *= dim;
|
| 20 |
+
}
|
| 21 |
+
return size;
|
| 22 |
+
};
|
| 23 |
+
/**
|
| 24 |
+
* implementation of Tensor.reshape()
|
| 25 |
+
*/
|
| 26 |
+
export const tensorReshape = (tensor, dims) => {
|
| 27 |
+
switch (tensor.location) {
|
| 28 |
+
case 'cpu':
|
| 29 |
+
return new Tensor(tensor.type, tensor.data, dims);
|
| 30 |
+
case 'cpu-pinned':
|
| 31 |
+
return new Tensor({
|
| 32 |
+
location: 'cpu-pinned',
|
| 33 |
+
data: tensor.data,
|
| 34 |
+
type: tensor.type,
|
| 35 |
+
dims,
|
| 36 |
+
});
|
| 37 |
+
case 'texture':
|
| 38 |
+
return new Tensor({
|
| 39 |
+
location: 'texture',
|
| 40 |
+
texture: tensor.texture,
|
| 41 |
+
type: tensor.type,
|
| 42 |
+
dims,
|
| 43 |
+
});
|
| 44 |
+
case 'gpu-buffer':
|
| 45 |
+
return new Tensor({
|
| 46 |
+
location: 'gpu-buffer',
|
| 47 |
+
gpuBuffer: tensor.gpuBuffer,
|
| 48 |
+
type: tensor.type,
|
| 49 |
+
dims,
|
| 50 |
+
});
|
| 51 |
+
case 'ml-tensor':
|
| 52 |
+
return new Tensor({
|
| 53 |
+
location: 'ml-tensor',
|
| 54 |
+
mlTensor: tensor.mlTensor,
|
| 55 |
+
type: tensor.type,
|
| 56 |
+
dims,
|
| 57 |
+
});
|
| 58 |
+
default:
|
| 59 |
+
throw new Error(`tensorReshape: tensor location ${tensor.location} is not supported`);
|
| 60 |
+
}
|
| 61 |
+
};
|
| 62 |
+
//# sourceMappingURL=tensor-utils-impl.js.map
|
runtime/vendor/onnxruntime-common/tensor-utils.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=tensor-utils.js.map
|
runtime/vendor/onnxruntime-common/tensor.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { Tensor as TensorImpl } from './tensor-impl.js';
|
| 4 |
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
| 5 |
+
export const Tensor = TensorImpl;
|
| 6 |
+
//# sourceMappingURL=tensor.js.map
|
runtime/vendor/onnxruntime-common/trace.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
import { env } from './env-impl.js';
|
| 4 |
+
/**
|
| 5 |
+
* @ignore
|
| 6 |
+
*/
|
| 7 |
+
export const TRACE = (deviceType, label) => {
|
| 8 |
+
if (typeof env.trace === 'undefined' ? !env.wasm.trace : !env.trace) {
|
| 9 |
+
return;
|
| 10 |
+
}
|
| 11 |
+
// eslint-disable-next-line no-console
|
| 12 |
+
console.timeStamp(`${deviceType}::ORT::${label}`);
|
| 13 |
+
};
|
| 14 |
+
const TRACE_FUNC = (msg, extraMsg) => {
|
| 15 |
+
const stack = new Error().stack?.split(/\r\n|\r|\n/g) || [];
|
| 16 |
+
let hasTraceFunc = false;
|
| 17 |
+
for (let i = 0; i < stack.length; i++) {
|
| 18 |
+
if (hasTraceFunc && !stack[i].includes('TRACE_FUNC')) {
|
| 19 |
+
let label = `FUNC_${msg}::${stack[i].trim().split(' ')[1]}`;
|
| 20 |
+
if (extraMsg) {
|
| 21 |
+
label += `::${extraMsg}`;
|
| 22 |
+
}
|
| 23 |
+
TRACE('CPU', label);
|
| 24 |
+
return;
|
| 25 |
+
}
|
| 26 |
+
if (stack[i].includes('TRACE_FUNC')) {
|
| 27 |
+
hasTraceFunc = true;
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
};
|
| 31 |
+
/**
|
| 32 |
+
* @ignore
|
| 33 |
+
*/
|
| 34 |
+
export const TRACE_FUNC_BEGIN = (extraMsg) => {
|
| 35 |
+
if (typeof env.trace === 'undefined' ? !env.wasm.trace : !env.trace) {
|
| 36 |
+
return;
|
| 37 |
+
}
|
| 38 |
+
TRACE_FUNC('BEGIN', extraMsg);
|
| 39 |
+
};
|
| 40 |
+
/**
|
| 41 |
+
* @ignore
|
| 42 |
+
*/
|
| 43 |
+
export const TRACE_FUNC_END = (extraMsg) => {
|
| 44 |
+
if (typeof env.trace === 'undefined' ? !env.wasm.trace : !env.trace) {
|
| 45 |
+
return;
|
| 46 |
+
}
|
| 47 |
+
TRACE_FUNC('END', extraMsg);
|
| 48 |
+
};
|
| 49 |
+
/**
|
| 50 |
+
* @ignore
|
| 51 |
+
*/
|
| 52 |
+
export const TRACE_EVENT_BEGIN = (extraMsg) => {
|
| 53 |
+
if (typeof env.trace === 'undefined' ? !env.wasm.trace : !env.trace) {
|
| 54 |
+
return;
|
| 55 |
+
}
|
| 56 |
+
// eslint-disable-next-line no-console
|
| 57 |
+
console.time(`ORT::${extraMsg}`);
|
| 58 |
+
};
|
| 59 |
+
/**
|
| 60 |
+
* @ignore
|
| 61 |
+
*/
|
| 62 |
+
export const TRACE_EVENT_END = (extraMsg) => {
|
| 63 |
+
if (typeof env.trace === 'undefined' ? !env.wasm.trace : !env.trace) {
|
| 64 |
+
return;
|
| 65 |
+
}
|
| 66 |
+
// eslint-disable-next-line no-console
|
| 67 |
+
console.timeEnd(`ORT::${extraMsg}`);
|
| 68 |
+
};
|
| 69 |
+
//# sourceMappingURL=trace.js.map
|
runtime/vendor/onnxruntime-common/type-helper.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
export {};
|
| 4 |
+
//# sourceMappingURL=type-helper.js.map
|
runtime/vendor/onnxruntime-common/version.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
| 2 |
+
// Licensed under the MIT License.
|
| 3 |
+
// This file is generated by /js/scripts/update-version.ts
|
| 4 |
+
// Do not modify file content manually.
|
| 5 |
+
export const version = '1.27.0';
|
| 6 |
+
//# sourceMappingURL=version.js.map
|
runtime/vendor/ort-wasm-simd-threaded.asyncify.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function ortWasmThreaded(moduleArg={}){var moduleRtn;var g=moduleArg,aa=!!globalThis.window,ba=!!globalThis.WorkerGlobalScope,l=globalThis.process?.versions?.node&&"renderer"!=globalThis.process?.type,n=ba&&self.name?.startsWith("em-pthread");if(l){const {createRequire:a}=await import("module");var require=a(import.meta.url),ca=require("worker_threads");global.Worker=ca.Worker;n=(ba=!ca.oe)&&"em-pthread"==ca.workerData}g.mountExternalData=(a,b)=>{a.startsWith("./")&&(a=a.substring(2));(g.Vc||(g.Vc=new Map)).set(a,b)};
|
| 2 |
+
g.unmountExternalData=()=>{delete g.Vc};var SharedArrayBuffer=globalThis.SharedArrayBuffer??(new WebAssembly.Memory({initial:0,maximum:0,shared:!0})).buffer.constructor;
|
| 3 |
+
let ea=()=>{const a=b=>(...c)=>{const d=q;c=b(...c);return q!=d?da():c};(b=>{for(const c of b)g[c]=a(g[c])})(["_OrtAppendExecutionProvider","_OrtCreateSession","_OrtRun","_OrtRunWithBinding","_OrtBindInput"]);"undefined"!==typeof jsepRunAsync&&(g._OrtRun=jsepRunAsync(g._OrtRun),g._OrtRunWithBinding=jsepRunAsync(g._OrtRunWithBinding));ea=void 0};g.asyncInit=()=>{ea?.()};var fa="./this.program",ha=(a,b)=>{throw b;},ia=import.meta.url,ja="",ka,la;
|
| 4 |
+
if(l){var fs=require("fs");ia.startsWith("file:")&&(ja=require("path").dirname(require("url").fileURLToPath(ia))+"/");la=a=>{a=ma(a)?new URL(a):a;return fs.readFileSync(a)};ka=async a=>{a=ma(a)?new URL(a):a;return fs.readFileSync(a,void 0)};1<process.argv.length&&(fa=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);ha=(a,b)=>{process.exitCode=a;throw b;}}else if(aa||ba){try{ja=(new URL(".",ia)).href}catch{}l||(ba&&(la=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";
|
| 5 |
+
b.send(null);return new Uint8Array(b.response)}),ka=async a=>{if(ma(a))return new Promise((c,d)=>{var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer";e.onload=()=>{200==e.status||0==e.status&&e.response?c(e.response):d(e.status)};e.onerror=d;e.send(null)});var b=await fetch(a,{credentials:"same-origin"});if(b.ok)return b.arrayBuffer();throw Error(b.status+" : "+b.url);})}var na=console.log.bind(console),oa=console.error.bind(console);
|
| 6 |
+
if(l){var pa=require("util"),qa=a=>"object"==typeof a?pa.inspect(a):a;na=(...a)=>fs.writeSync(1,a.map(qa).join(" ")+"\n");oa=(...a)=>fs.writeSync(2,a.map(qa).join(" ")+"\n")}var ra=na,t=oa,sa,ta,ua=!1,va,ma=a=>a.startsWith("file://");function u(){v.buffer!=w.buffer&&wa()}var xa,ya;
|
| 7 |
+
if(l&&n){var Aa=ca.parentPort;Aa.on("message",a=>global.onmessage?.({data:a}));Object.assign(globalThis,{self:global,postMessage:a=>Aa.postMessage(a)});process.on("uncaughtException",a=>{postMessage({Pc:"uncaughtException",error:a});process.exit(1)})}var Ba;
|
| 8 |
+
if(n){var Ca=!1;self.onunhandledrejection=b=>{throw b.reason||b;};function a(b){try{var c=b.data,d=c.Pc;if("load"===d){let e=[];self.onmessage=f=>e.push(f);Ba=()=>{postMessage({Pc:"loaded"});for(let f of e)a(f);self.onmessage=a};for(const f of c.ee)if(!g[f]||g[f].proxy)g[f]=(...h)=>{postMessage({Pc:"callHandler",de:f,args:h})},"print"==f&&(ra=g[f]),"printErr"==f&&(t=g[f]);v=c.ke;wa();ta=c.le;Da();Ea()}else if("run"===d){Fa(c.Oc);Ga(c.Oc,0,0,1,0,0);Ha();Ia(c.Oc);Ca||(Ja(),Ca=!0);try{Ka(c.ie,c.Xc)}catch(e){if("unwind"!=
|
| 9 |
+
e)throw e;}}else"setimmediate"!==c.target&&("checkMailbox"===d?Ca&&La():d&&(t(`worker: received unknown command ${d}`),t(c)))}catch(e){throw Ma(),e;}}self.onmessage=a}var w,x,Na,Oa,A,B,Pa,E,F,Qa,Ra=!1;function wa(){var a=v.buffer;g.HEAP8=w=new Int8Array(a);Na=new Int16Array(a);g.HEAPU8=x=new Uint8Array(a);Oa=new Uint16Array(a);g.HEAP32=A=new Int32Array(a);g.HEAPU32=B=new Uint32Array(a);Pa=new Float32Array(a);E=new Float64Array(a);F=new BigInt64Array(a);Qa=new BigUint64Array(a)}
|
| 10 |
+
function Sa(){Ra=!0;n?Ba():G.$b()}function Ta(a){a="Aborted("+a+")";t(a);ua=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ya?.(a);throw a;}var Ua;async function Va(a){if(!sa)try{var b=await ka(a);return new Uint8Array(b)}catch{}if(a==Ua&&sa)a=new Uint8Array(sa);else if(la)a=la(a);else throw"both async and sync fetching of the wasm failed";return a}
|
| 11 |
+
async function Wa(a,b){try{var c=await Va(a);return await WebAssembly.instantiate(c,b)}catch(d){t(`failed to asynchronously prepare wasm: ${d}`),Ta(d)}}async function Xa(a){var b=Ua;if(!sa&&!ma(b)&&!l)try{var c=fetch(b,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(c,a)}catch(d){t(`wasm streaming compile failed: ${d}`),t("falling back to ArrayBuffer instantiation")}return Wa(b,a)}
|
| 12 |
+
function Ya(){Za={f:$a,J:ab,k:bb,p:cb,l:db,sa:eb,b:fb,ca:gb,Ja:hb,q:ib,da:jb,Za:kb,Fa:lb,Ha:mb,_a:nb,Xa:ob,Qa:pb,Wa:qb,oa:rb,Ga:sb,Yb:tb,Ya:ub,Zb:vb,db:wb,Da:xb,Tb:zb,Rb:Ab,Ca:Cb,M:Db,I:Eb,Sb:Fb,ja:Gb,Ub:Hb,Ta:Ib,Wb:Jb,Ka:Kb,Pb:Lb,ka:Mb,Sa:Ia,ab:Nb,U:Ob,n:Pb,c:Qb,rb:Rb,w:Sb,L:Tb,z:Ub,j:Vb,o:Wb,sb:Xb,G:Yb,T:Zb,h:$b,u:ac,m:bc,i:cc,Na:dc,Oa:ec,Pa:fc,La:gc,Ma:hc,Qb:ic,eb:jc,cb:kc,Y:lc,qb:mc,la:nc,bb:oc,fb:pc,$a:qc,Xb:rc,N:sc,gb:tc,X:uc,Vb:vc,nb:wc,C:xc,ra:yc,qa:zc,pb:Ac,W:Bc,v:Cc,mb:Dc,lb:Ec,kb:Fc,ob:Gc,
|
| 13 |
+
jb:Hc,ib:Ic,hb:Jc,Ua:Kc,Va:Lc,Ia:Mc,V:Nc,na:Oc,Ra:Pc,ma:Qc,Cb:Rc,xa:Sc,Db:Tc,ya:Uc,F:Vc,e:Wc,s:Xc,x:Yc,B:Zc,Fb:$c,ba:ad,D:bd,za:cd,$:dd,ga:ed,Gb:fd,Hb:gd,Ba:hd,Aa:jd,Ib:kd,wa:ld,aa:md,d:nd,A:od,r:pd,Bb:qd,t:rd,y:sd,H:td,E:ud,K:vd,R:wd,ia:xd,_:yd,Kb:zd,Lb:Ad,Jb:Bd,g:Cd,a:v,Ob:Dd,Eb:Ed,ha:Fd,O:Gd,pa:Hd,Mb:Id,ta:Jd,Q:Kd,yb:Ld,zb:Md,ua:Nd,ea:Od,P:Pd,Ea:Qd,va:Rd,Z:Sd,wb:Td,_b:Ud,S:Vd,Ab:Wd,tb:Xd,ub:Yd,vb:Zd,fa:$d,xb:ae,Nb:be};return{a:Za}}
|
| 14 |
+
async function Da(){function a(d,e){var f=G=d.exports;d={};for(let [h,k]of Object.entries(f))"function"==typeof k?(f=ce(k),d[h]=f):d[h]=k;G=d;G=de();ee.push(G.jd);d=G;fe=d.ac;Ja=d.bc;g._OrtInit=d.cc;g._OrtGetLastError=d.dc;g._OrtCreateSessionOptions=d.ec;g._OrtAppendExecutionProvider=d.fc;g._OrtAddFreeDimensionOverride=d.gc;g._OrtAddSessionConfigEntry=d.hc;g._OrtReleaseSessionOptions=d.ic;g._OrtCreateSession=d.jc;g._OrtReleaseSession=d.kc;g._OrtGetInputOutputCount=d.lc;g._OrtGetInputOutputMetadata=
|
| 15 |
+
d.mc;g._OrtFree=d.nc;g._OrtCreateTensor=d.oc;g._OrtGetTensorData=d.pc;g._OrtReleaseTensor=d.qc;g._OrtCreateRunOptions=d.rc;g._OrtAddRunConfigEntry=d.sc;g._OrtReleaseRunOptions=d.tc;g._OrtCreateBinding=d.uc;g._OrtBindInput=d.vc;g._OrtBindOutput=d.wc;g._OrtClearBoundOutputs=d.xc;g._OrtReleaseBinding=d.yc;g._OrtRunWithBinding=d.zc;g._OrtRun=d.Ac;g._OrtEndProfiling=d.Bc;ge=g._OrtGetWebGpuDevice=d.Cc;he=d.Dc;H=g._free=d.Ec;ie=g._malloc=d.Fc;je=g._wgpuBufferRelease=d.Gc;ke=g._wgpuCreateInstance=d.Hc;le=
|
| 16 |
+
d.Ic;me=d.Jc;ne=d.Kc;oe=d.Lc;pe=d.Mc;qe=d.Qc;re=d._c;se=d.$c;te=d.ad;ue=d.cd;ve=d.dd;we=d.ed;xe=d.fd;ye=d.gd;ze=d.hd;Ae=d.id;Ga=d.ld;Ma=d.md;Be=d.nd;Ce=d.od;De=d.pd;Ee=d.qd;Fe=d.rd;Ge=d.sd;I=d.td;He=d.ud;Ie=d.vd;J=d.wd;Je=d.xd;K=d.yd;Ke=d.zd;Le=d.Ad;Me=d.Bd;Ne=d.Cd;dynCall_vii=d.Dd;Oe=d.Ed;dynCall_v=d.Fd;Pe=d.Gd;Qe=d.Hd;Re=d.Id;dynCall_iii=d.Jd;Se=d.Kd;Te=d.Ld;Ue=d.Md;dynCall_vi=d.Nd;Ve=d.Od;We=d.Pd;Xe=d.Qd;Ye=d.Rd;Ze=d.Sd;$e=d.Ud;af=d.Vd;bf=d.Wd;cf=d.Xd;df=d.Zd;ef=d._d;ff=d.$d;gf=d.ae;hf=d.be;jf=
|
| 17 |
+
d.ce;kf=d.qe;lf=d.re;mf=d.se;nf=d.te;of=d.ue;pf=d.ve;qf=d.we;rf=d.xe;sf=d.ye;tf=d.ze;uf=d.Ae;vf=d.$e;wf=d.af;xf=d.bf;yf=d.cf;ta=e;return G}var b=Ya();if(g.instantiateWasm)return new Promise(d=>{g.instantiateWasm(b,(e,f)=>{d(a(e,f))})});if(n){var c=new WebAssembly.Instance(ta,Ya());return a(c,ta)}Ua??=g.locateFile?g.locateFile?g.locateFile("ort-wasm-simd-threaded.asyncify.wasm",ja):ja+"ort-wasm-simd-threaded.asyncify.wasm":(new URL("ort-wasm-simd-threaded.asyncify.wasm",import.meta.url)).href;
|
| 18 |
+
return function(d){return a(d.instance,d.module)}(await Xa(b))}class zf{name="ExitStatus";constructor(a){this.message=`Program terminated with exit(${a})`;this.status=a}}
|
| 19 |
+
var Af=a=>{a.terminate();a.onmessage=()=>{}},Bf=[],Cf=0,Df=null,Jf=a=>{0==Ef.length&&(Ff(),Gf(Ef[0]));var b=Ef.pop();if(!b)return 6;Hf.push(b);If[a.Oc]=b;b.Oc=a.Oc;var c={Pc:"run",ie:a.he,Xc:a.Xc,Oc:a.Oc};l&&b.unref();b.postMessage(c,a.Zc);return 0},L=0,M=(a,b,...c)=>{var d=16*c.length,e=K(),f=Je(d),h=f>>>3,k;for(k of c)"bigint"==typeof k?((u(),F)[h++>>>0]=1n,(u(),F)[h++>>>0]=k):((u(),F)[h++>>>0]=0n,(u(),E)[h++>>>0]=k);a=Be(a,0,d,f,b);J(e);return a};
|
| 20 |
+
function Dd(a){if(n)return M(0,1,a);va=a;if(!(0<L)){for(var b of Hf)Af(b);for(b of Ef)Af(b);Ef=[];Hf=[];If={};ua=!0}ha(a,new zf(a))}function Kf(a){if(n)return M(1,0,a);Mc(a)}var Mc=a=>{va=a;if(n)throw Kf(a),"unwind";Dd(a)},Ef=[],Hf=[],ee=[],If={};function Lf(){for(var a=g.numThreads-1;a--;)Ff();Bf.push(async()=>{var b=Mf();Cf++;await b;Cf--;0==Cf&&Df&&(b=Df,Df=null,b())})}var Nf=a=>{var b=a.Oc;delete If[b];Ef.push(a);Hf.splice(Hf.indexOf(a),1);a.Oc=0;Ce(b)};function Ha(){ee.forEach(a=>a())}
|
| 21 |
+
var Gf=a=>new Promise(b=>{a.onmessage=f=>{var h=f.data;f=h.Pc;if(h.Wc&&h.Wc!=he()){var k=If[h.Wc];k?k.postMessage(h,h.Zc):t(`Internal error! Worker sent a message "${f}" to target pthread ${h.Wc}, but that thread no longer exists!`)}else if("checkMailbox"===f)La();else if("spawnThread"===f)Jf(h);else if("cleanupThread"===f)N(()=>{Nf(If[h.je])});else if("loaded"===f)a.loaded=!0,l&&!a.Oc&&a.unref(),b(a);else if("setimmediate"===h.target)a.postMessage(h);else if("uncaughtException"===f)a.onerror(h.error);
|
| 22 |
+
else if("callHandler"===f)g[h.de](...h.args);else f&&t(`worker sent an unknown command ${f}`)};a.onerror=f=>{t(`${"worker sent an error!"} ${f.filename}:${f.lineno}: ${f.message}`);throw f;};l&&(a.on("message",f=>a.onmessage({data:f})),a.on("error",f=>a.onerror(f)));var c=[],d=[],e;for(e of d)g.propertyIsEnumerable(e)&&c.push(e);a.postMessage({Pc:"load",ee:c,ke:v,le:ta})});async function Mf(){if(!n)return Promise.all(Ef.map(Gf))}
|
| 23 |
+
function Ff(){var a=new Worker(new URL(import.meta.url),{type:"module",workerData:"em-pthread",name:"em-pthread"});Ef.push(a)}function Fa(a){var b=(u(),B)[a+52>>>2>>>0];a=(u(),B)[a+56>>>2>>>0];Ie(b,b-a);J(b)}var Ka=(a,b)=>{L=0;a=Oe(a,b);0<L?va=a:De(a)},v,Of=[],Pf=0,O=a=>-9007199254740992>a||9007199254740992<a?NaN:Number(a);function $a(a){a>>>=0;var b=new Qf(a);0==(u(),w)[b.Rc+12>>>0]&&(Rf(b,!0),Pf--);Sf(b,!1);Of.push(b);return Ne(a)}
|
| 24 |
+
var Tf=0,ab=()=>{I(0,0);var a=Of.pop();Ke(a.Yc);Tf=0};function Rf(a,b){b=b?1:0;(u(),w)[a.Rc+12>>>0]=b}function Sf(a,b){b=b?1:0;(u(),w)[a.Rc+13>>>0]=b}class Qf{constructor(a){this.Yc=a;this.Rc=a-24}}var Uf=a=>{var b=Tf;if(!b)return He(0),0;var c=new Qf(b);(u(),B)[c.Rc+16>>>2>>>0]=b;var d=(u(),B)[c.Rc+4>>>2>>>0];if(!d)return He(0),b;for(var e of a){if(0===e||e===d)break;if(Me(e,d,c.Rc+16))return He(e),b}He(d);return b};function bb(){return Uf([])}function cb(a){return Uf([a>>>0])}
|
| 25 |
+
function db(a,b,c,d){return Uf([a>>>0,b>>>0,c>>>0,d>>>0])}var eb=()=>{var a=Of.pop();a||Ta("no exception to throw");var b=a.Yc;0==(u(),w)[a.Rc+13>>>0]&&(Of.push(a),Sf(a,!0),Rf(a,!1),Pf++);Le(b);Tf=b;throw Tf;};function fb(a,b,c){a>>>=0;var d=new Qf(a);b>>>=0;c>>>=0;(u(),B)[d.Rc+16>>>2>>>0]=0;(u(),B)[d.Rc+4>>>2>>>0]=b;(u(),B)[d.Rc+8>>>2>>>0]=c;Le(a);Tf=a;Pf++;throw Tf;}var gb=()=>Pf;function Vf(a,b,c,d){return n?M(2,1,a,b,c,d):hb(a,b,c,d)}
|
| 26 |
+
function hb(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;if(!globalThis.SharedArrayBuffer)return 6;var e=[];if(n&&0===e.length)return Vf(a,b,c,d);a={he:c,Oc:a,Xc:d,Zc:e};return n?(a.Pc="spawnThread",postMessage(a,e),0):Jf(a)}function ib(a){Tf||=a>>>0;throw Tf;}
|
| 27 |
+
var Wf=globalThis.TextDecoder&&new TextDecoder,Xf=(a,b,c,d)=>{c=b+c;if(d)return c;for(;a[b]&&!(b>=c);)++b;return b},Yf=(a,b=0,c,d)=>{b>>>=0;c=Xf(a,b,c,d);if(16<c-b&&a.buffer&&Wf)return Wf.decode(a.buffer instanceof ArrayBuffer?a.subarray(b,c):a.slice(b,c));for(d="";b<c;){var e=a[b++];if(e&128){var f=a[b++]&63;if(192==(e&224))d+=String.fromCharCode((e&31)<<6|f);else{var h=a[b++]&63;e=224==(e&240)?(e&15)<<12|f<<6|h:(e&7)<<18|f<<12|h<<6|a[b++]&63;65536>e?d+=String.fromCharCode(e):(e-=65536,d+=String.fromCharCode(55296|
|
| 28 |
+
e>>10,56320|e&1023))}}else d+=String.fromCharCode(e)}return d},Zf=(a,b,c)=>(a>>>=0)?Yf((u(),x),a,b,c):"";function jb(a,b,c){return n?M(3,1,a,b,c):0}function kb(a,b){if(n)return M(4,1,a,b)}function lb(a,b){if(n)return M(5,1,a,b)}function mb(a,b,c){if(n)return M(6,1,a,b,c)}function nb(a,b,c){return n?M(7,1,a,b,c):0}function ob(a,b){if(n)return M(8,1,a,b)}function pb(a,b,c){if(n)return M(9,1,a,b,c)}function qb(a,b,c,d){if(n)return M(10,1,a,b,c,d)}function rb(a,b,c,d){if(n)return M(11,1,a,b,c,d)}
|
| 29 |
+
function sb(a,b,c,d){if(n)return M(12,1,a,b,c,d)}function tb(a){if(n)return M(13,1,a)}function ub(a,b){if(n)return M(14,1,a,b)}function vb(a,b,c){if(n)return M(15,1,a,b,c)}var wb=()=>Ta(""),P=a=>{a>>>=0;for(var b="";;){var c=(u(),x)[a++>>>0];if(!c)return b;b+=String.fromCharCode(c)}},$f={},ag={},bg={},cg=class extends Error{constructor(a){super(a);this.name="BindingError"}};
|
| 30 |
+
function dg(a,b,c={}){var d=b.name;if(!a)throw new cg(`type "${d}" must have a positive integer typeid pointer`);if(ag.hasOwnProperty(a)){if(c.fe)return;throw new cg(`Cannot register type '${d}' twice`);}ag[a]=b;delete bg[a];$f.hasOwnProperty(a)&&(b=$f[a],delete $f[a],b.forEach(e=>e()))}function Q(a,b,c={}){return dg(a,b,c)}
|
| 31 |
+
var eg=(a,b,c)=>{switch(b){case 1:return c?d=>(u(),w)[d>>>0]:d=>(u(),x)[d>>>0];case 2:return c?d=>(u(),Na)[d>>>1>>>0]:d=>(u(),Oa)[d>>>1>>>0];case 4:return c?d=>(u(),A)[d>>>2>>>0]:d=>(u(),B)[d>>>2>>>0];case 8:return c?d=>(u(),F)[d>>>3>>>0]:d=>(u(),Qa)[d>>>3>>>0];default:throw new TypeError(`invalid integer width (${b}): ${a}`);}};
|
| 32 |
+
function xb(a,b,c,d,e){a>>>=0;c>>>=0;b=P(b>>>0);d=0n===d;let f=h=>h;if(d){const h=8*c;f=k=>BigInt.asUintN(h,k);e=f(e)}Q(a,{name:b,Nc:f,Tc:(h,k)=>{"number"==typeof k&&(k=BigInt(k));return k},Sc:eg(b,c,!d),Uc:null})}function zb(a,b,c,d){a>>>=0;b=P(b>>>0);Q(a,{name:b,Nc:function(e){return!!e},Tc:function(e,f){return f?c:d},Sc:function(e){return this.Nc((u(),x)[e>>>0])},Uc:null})}var fg=[],gg=[0,1,,1,null,1,!0,1,!1,1];function Qb(a){a>>>=0;9<a&&0===--gg[a+1]&&(gg[a]=void 0,fg.push(a))}
|
| 33 |
+
var R=a=>{if(!a)throw new cg(`Cannot use deleted val. handle = ${a}`);return gg[a]},S=a=>{switch(a){case void 0:return 2;case null:return 4;case !0:return 6;case !1:return 8;default:const b=fg.pop()||gg.length;gg[b]=a;gg[b+1]=1;return b}};function hg(a){return this.Nc((u(),B)[a>>>2>>>0])}var ig={name:"emscripten::val",Nc:a=>{var b=R(a);Qb(a);return b},Tc:(a,b)=>S(b),Sc:hg,Uc:null};function Ab(a){return Q(a>>>0,ig)}
|
| 34 |
+
var jg=(a,b)=>{switch(b){case 4:return function(c){return this.Nc((u(),Pa)[c>>>2>>>0])};case 8:return function(c){return this.Nc((u(),E)[c>>>3>>>0])};default:throw new TypeError(`invalid float width (${b}): ${a}`);}};function Cb(a,b,c){a>>>=0;c>>>=0;b=P(b>>>0);Q(a,{name:b,Nc:d=>d,Tc:(d,e)=>e,Sc:jg(b,c),Uc:null})}function Db(a,b,c,d,e){a>>>=0;c>>>=0;b=P(b>>>0);let f=k=>k;if(0===d){var h=32-8*c;f=k=>k<<h>>>h;e=f(e)}Q(a,{name:b,Nc:f,Tc:(k,m)=>m,Sc:eg(b,c,0!==d),Uc:null})}
|
| 35 |
+
function Eb(a,b,c){function d(f){var h=(u(),B)[f>>>2>>>0];f=(u(),B)[f+4>>>2>>>0];return new e((u(),w).buffer,f,h)}a>>>=0;var e=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array][b];c=P(c>>>0);Q(a,{name:c,Nc:d,Sc:d},{fe:!0})}
|
| 36 |
+
var T=(a,b,c)=>{var d=(u(),x);b>>>=0;if(0<c){var e=b;c=b+c-1;for(var f=0;f<a.length;++f){var h=a.codePointAt(f);if(127>=h){if(b>=c)break;d[b++>>>0]=h}else if(2047>=h){if(b+1>=c)break;d[b++>>>0]=192|h>>6;d[b++>>>0]=128|h&63}else if(65535>=h){if(b+2>=c)break;d[b++>>>0]=224|h>>12;d[b++>>>0]=128|h>>6&63;d[b++>>>0]=128|h&63}else{if(b+3>=c)break;d[b++>>>0]=240|h>>18;d[b++>>>0]=128|h>>12&63;d[b++>>>0]=128|h>>6&63;d[b++>>>0]=128|h&63;f++}}d[b>>>0]=0;a=b-e}else a=0;return a},U=a=>{for(var b=0,c=0;c<a.length;++c){var d=
|
| 37 |
+
a.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}return b};
|
| 38 |
+
function Fb(a,b){a>>>=0;b=P(b>>>0);Q(a,{name:b,Nc(c){var d=(u(),B)[c>>>2>>>0];d=Zf(c+4,d,!0);H(c);return d},Tc(c,d){d instanceof ArrayBuffer&&(d=new Uint8Array(d));var e="string"==typeof d;if(!(e||ArrayBuffer.isView(d)&&1==d.BYTES_PER_ELEMENT))throw new cg("Cannot pass non-string to std::string");var f=e?U(d):d.length;var h=ie(4+f+1),k=h+4;(u(),B)[h>>>2>>>0]=f;e?T(d,k,f+1):(u(),x).set(d,k>>>0);null!==c&&c.push(H,h);return h},Sc:hg,Uc(c){H(c)}})}
|
| 39 |
+
var kg=globalThis.TextDecoder?new TextDecoder("utf-16le"):void 0,lg=(a,b,c)=>{a>>>=1;b=Xf((u(),Oa),a,b/2,c);if(16<b-a&&kg)return kg.decode((u(),Oa).slice(a,b));for(c="";a<b;++a){var d=(u(),Oa)[a>>>0];c+=String.fromCharCode(d)}return c},mg=(a,b,c)=>{c??=2147483647;if(2>c)return 0;c-=2;var d=b;c=c<2*a.length?c/2:a.length;for(var e=0;e<c;++e){var f=a.charCodeAt(e);(u(),Na)[b>>>1>>>0]=f;b+=2}(u(),Na)[b>>>1>>>0]=0;return b-d},ng=a=>2*a.length,og=(a,b,c)=>{var d="";a>>>=2;for(var e=0;!(e>=b/4);e++){var f=
|
| 40 |
+
(u(),B)[a+e>>>0];if(!f&&!c)break;d+=String.fromCodePoint(f)}return d},pg=(a,b,c)=>{b>>>=0;c??=2147483647;if(4>c)return 0;var d=b;c=d+c-4;for(var e=0;e<a.length;++e){var f=a.codePointAt(e);65535<f&&e++;(u(),A)[b>>>2>>>0]=f;b+=4;if(b+4>c)break}(u(),A)[b>>>2>>>0]=0;return b-d},qg=a=>{for(var b=0,c=0;c<a.length;++c)65535<a.codePointAt(c)&&c++,b+=4;return b};
|
| 41 |
+
function Gb(a,b,c){a>>>=0;b>>>=0;c>>>=0;c=P(c);if(2===b){var d=lg;var e=mg;var f=ng}else d=og,e=pg,f=qg;Q(a,{name:c,Nc:h=>{var k=(u(),B)[h>>>2>>>0];k=d(h+4,k*b,!0);H(h);return k},Tc:(h,k)=>{if("string"!=typeof k)throw new cg(`Cannot pass non-string to C++ string type ${c}`);var m=f(k),p=ie(4+m+b);(u(),B)[p>>>2>>>0]=m/b;e(k,p+4,m+b);null!==h&&h.push(H,p);return p},Sc:hg,Uc(h){H(h)}})}function Hb(a,b){a>>>=0;b=P(b>>>0);Q(a,{ge:!0,name:b,Nc:()=>{},Tc:()=>{}})}
|
| 42 |
+
function Ib(a){Ga(a>>>0,!ba,1,!aa,131072,!1);Ha()}var N=a=>{if(!ua)try{if(a(),!(0<L))try{n?he()&&De(va):Mc(va)}catch(b){b instanceof zf||"unwind"==b||ha(1,b)}}catch(b){b instanceof zf||"unwind"==b||ha(1,b)}},rg=!Atomics.waitAsync||globalThis.navigator?.userAgent&&91>Number((navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)||[])[2]);function Ia(a){a>>>=0;rg||(Atomics.waitAsync((u(),A),a>>>2,a).value.then(La),a+=128,Atomics.store((u(),A),a>>>2,1))}var La=()=>N(()=>{var a=he();a&&(Ia(a),Fe())});
|
| 43 |
+
function Jb(a,b){a>>>=0;a==b>>>0?setTimeout(La):n?postMessage({Wc:a,Pc:"checkMailbox"}):(a=If[a])&&a.postMessage({Pc:"checkMailbox"})}var sg=[];function Kb(a,b,c,d,e){b>>>=0;e>>>=0;sg.length=0;c=e>>>3;for(d=e+d>>>3;c<d;){var f;(u(),F)[c++>>>0]?f=(u(),F)[c++>>>0]:f=(u(),E)[c++>>>0];sg.push(f)}return(b?tg[b]:ug[a])(...sg)}var Lb=()=>{L=0};function Mb(a){a>>>=0;n?postMessage({Pc:"cleanupThread",je:a}):Nf(If[a])}function Nb(a){l&&If[a>>>0].ref()}var vg=a=>{try{a()}catch(b){Ta(b)}};
|
| 44 |
+
function ce(a){var b=(...c)=>{wg.push(a);try{return a(...c)}finally{ua||(wg.pop(),q&&1===xg&&0===wg.length&&(xg=0,L+=1,vg(wf),"undefined"!=typeof Fibers&&Fibers.De()))}};yg.set(a,b);return b}var xg=0,q=null,zg=0,wg=[],Ag=new Map,Bg=new Map,yg=new Map,Cg=0,Dg=null,Eg=[];function da(){return new Promise((a,b)=>{Dg={resolve:a,reject:b}})}
|
| 45 |
+
function Fg(){var a=ie(65548),b=a+12;(u(),B)[a>>>2>>>0]=b;(u(),B)[a+4>>>2>>>0]=b+65536;b=wg[0];if(!Ag.has(b)){var c=Cg++;Ag.set(b,c);Bg.set(c,b)}b=Ag.get(b);(u(),A)[a+8>>>2>>>0]=b;return a}function Gg(){var a=(u(),A)[q+8>>>2>>>0];a=Bg.get(a);a=yg.get(a);--L;return a()}
|
| 46 |
+
function Hg(a){if(!ua){if(0===xg){var b=!1,c=!1;a((d=0)=>{if(!ua&&(zg=d,b=!0,c)){xg=2;vg(()=>xf(q));"undefined"!=typeof MainLoop&&MainLoop.Yd&&MainLoop.resume();d=!1;try{var e=Gg()}catch(k){e=k,d=!0}var f=!1;if(!q){var h=Dg;h&&(Dg=null,(d?h.reject:h.resolve)(e),f=!0)}if(d&&!f)throw e;}});c=!0;b||(xg=1,q=Fg(),"undefined"!=typeof MainLoop&&MainLoop.Yd&&MainLoop.pause(),vg(()=>vf(q)))}else 2===xg?(xg=0,vg(yf),H(q),q=null,Eg.forEach(N)):Ta(`invalid state: ${xg}`);return zg}}var Ig=a=>Hg(b=>{a().then(b)});
|
| 47 |
+
function Ob(a){a>>>=0;return Ig(async()=>{var b=await R(a);return S(b)})}var Jg=[],Kg=a=>{var b=Jg.length;Jg.push(a);return b},Lg=(a,b)=>{for(var c=Array(a),d=0;d<a;++d){var e=d,f=(u(),B)[b+4*d>>>2>>>0],h=ag[f];if(void 0===h)throw a=`parameter ${d}`,f=fe(f),b=P(f),H(f),new cg(`${a} has unknown type ${b}`);c[e]=h}return c},Mg=(a,b,c)=>{var d=[];a=a(d,c);d.length&&((u(),B)[b>>>2>>>0]=S(d));return a},Ng={},Og=a=>{var b=Ng[a];return void 0===b?P(a):b};
|
| 48 |
+
function Pb(a,b,c){var [d,...e]=Lg(a,b>>>0);b=d.Tc.bind(d);var f=e.map(m=>m.Sc.bind(m));a--;var h={toValue:R};a=f.map((m,p)=>{var C=`argFromPtr${p}`;h[C]=m;return`${C}(args${p?"+"+8*p:""})`});switch(c){case 0:var k="toValue(handle)";break;case 2:k="new (toValue(handle))";break;case 3:k="";break;case 1:h.getStringOrSymbol=Og,k="toValue(handle)[getStringOrSymbol(methodName)]"}k+=`(${a})`;d.ge||(h.toReturnWire=b,h.emval_returnValue=Mg,k=`return emval_returnValue(toReturnWire, destructorsRef, ${k})`);
|
| 49 |
+
k=`return function (handle, methodName, destructorsRef, args) {\n ${k}\n }`;c=(new Function(Object.keys(h),k))(...Object.values(h));k=`methodCaller<(${e.map(m=>m.name)}) => ${d.name}>`;return Kg(Object.defineProperty(c,"name",{value:k}))}function Rb(a,b){b>>>=0;a=R(a>>>0);b=R(b);return a==b}function Sb(a){a>>>=0;if(!a)return S(globalThis);a=Og(a);return S(globalThis[a])}function Tb(a){a=Og(a>>>0);return S(g[a])}function Ub(a,b){b>>>=0;a=R(a>>>0);b=R(b);return S(a[b])}
|
| 50 |
+
function Vb(a){a>>>=0;9<a&&(gg[a+1]+=1)}function Wb(a,b,c,d,e){return Jg[a>>>0](b>>>0,c>>>0,d>>>0,e>>>0)}function Xb(a,b,c,d,e){return Wb(a>>>0,b>>>0,c>>>0,d>>>0,e>>>0)}function Yb(){return S([])}function Zb(a){a=R(a>>>0);for(var b=Array(a.length),c=0;c<a.length;c++)b[c]=a[c];return S(b)}function $b(a){return S(Og(a>>>0))}function ac(){return S({})}function bc(a){a>>>=0;for(var b=R(a);b.length;){var c=b.pop();b.pop()(c)}Qb(a)}function cc(a,b,c){b>>>=0;c>>>=0;a=R(a>>>0);b=R(b);c=R(c);a[b]=c}
|
| 51 |
+
function dc(a,b){a=O(a);b>>>=0;a=new Date(1E3*a);(u(),A)[b>>>2>>>0]=a.getUTCSeconds();(u(),A)[b+4>>>2>>>0]=a.getUTCMinutes();(u(),A)[b+8>>>2>>>0]=a.getUTCHours();(u(),A)[b+12>>>2>>>0]=a.getUTCDate();(u(),A)[b+16>>>2>>>0]=a.getUTCMonth();(u(),A)[b+20>>>2>>>0]=a.getUTCFullYear()-1900;(u(),A)[b+24>>>2>>>0]=a.getUTCDay();a=(a.getTime()-Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0))/864E5|0;(u(),A)[b+28>>>2>>>0]=a}
|
| 52 |
+
var Pg=a=>0===a%4&&(0!==a%100||0===a%400),Qg=[0,31,60,91,121,152,182,213,244,274,305,335],Rg=[0,31,59,90,120,151,181,212,243,273,304,334];
|
| 53 |
+
function ec(a,b){a=O(a);b>>>=0;a=new Date(1E3*a);(u(),A)[b>>>2>>>0]=a.getSeconds();(u(),A)[b+4>>>2>>>0]=a.getMinutes();(u(),A)[b+8>>>2>>>0]=a.getHours();(u(),A)[b+12>>>2>>>0]=a.getDate();(u(),A)[b+16>>>2>>>0]=a.getMonth();(u(),A)[b+20>>>2>>>0]=a.getFullYear()-1900;(u(),A)[b+24>>>2>>>0]=a.getDay();var c=(Pg(a.getFullYear())?Qg:Rg)[a.getMonth()]+a.getDate()-1|0;(u(),A)[b+28>>>2>>>0]=c;(u(),A)[b+36>>>2>>>0]=-(60*a.getTimezoneOffset());c=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();var d=(new Date(a.getFullYear(),
|
| 54 |
+
0,1)).getTimezoneOffset();a=(c!=d&&a.getTimezoneOffset()==Math.min(d,c))|0;(u(),A)[b+32>>>2>>>0]=a}
|
| 55 |
+
function fc(a){a>>>=0;var b=new Date((u(),A)[a+20>>>2>>>0]+1900,(u(),A)[a+16>>>2>>>0],(u(),A)[a+12>>>2>>>0],(u(),A)[a+8>>>2>>>0],(u(),A)[a+4>>>2>>>0],(u(),A)[a>>>2>>>0],0),c=(u(),A)[a+32>>>2>>>0],d=b.getTimezoneOffset(),e=(new Date(b.getFullYear(),6,1)).getTimezoneOffset(),f=(new Date(b.getFullYear(),0,1)).getTimezoneOffset(),h=Math.min(f,e);0>c?(u(),A)[a+32>>>2>>>0]=Number(e!=f&&h==d):0<c!=(h==d)&&(e=Math.max(f,e),b.setTime(b.getTime()+6E4*((0<c?h:e)-d)));(u(),A)[a+24>>>2>>>0]=b.getDay();c=(Pg(b.getFullYear())?
|
| 56 |
+
Qg:Rg)[b.getMonth()]+b.getDate()-1|0;(u(),A)[a+28>>>2>>>0]=c;(u(),A)[a>>>2>>>0]=b.getSeconds();(u(),A)[a+4>>>2>>>0]=b.getMinutes();(u(),A)[a+8>>>2>>>0]=b.getHours();(u(),A)[a+12>>>2>>>0]=b.getDate();(u(),A)[a+16>>>2>>>0]=b.getMonth();(u(),A)[a+20>>>2>>>0]=b.getYear();a=b.getTime();return BigInt(isNaN(a)?-1:a/1E3)}function gc(a,b,c,d,e,f,h){return n?M(16,1,a,b,c,d,e,f,h):-52}function hc(a,b,c,d,e,f){if(n)return M(17,1,a,b,c,d,e,f)}var Sg={},sc=()=>performance.timeOrigin+performance.now();
|
| 57 |
+
function ic(a,b){if(n)return M(18,1,a,b);Sg[a]&&(clearTimeout(Sg[a].id),delete Sg[a]);if(!b)return 0;var c=setTimeout(()=>{delete Sg[a];N(()=>Ee(a,performance.timeOrigin+performance.now()))},b);Sg[a]={id:c,Ce:b};return 0}
|
| 58 |
+
function jc(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;var e=(new Date).getFullYear(),f=(new Date(e,0,1)).getTimezoneOffset();e=(new Date(e,6,1)).getTimezoneOffset();var h=Math.max(f,e);(u(),B)[a>>>2>>>0]=60*h;(u(),A)[b>>>2>>>0]=Number(f!=e);b=k=>{var m=Math.abs(k);return`UTC${0<=k?"-":"+"}${String(Math.floor(m/60)).padStart(2,"0")}${String(m%60).padStart(2,"0")}`};a=b(f);b=b(e);e<f?(T(a,c,17),T(b,d,17)):(T(a,d,17),T(b,c,17))}var oc=()=>Date.now(),Tg=1;
|
| 59 |
+
function kc(a,b,c){c>>>=0;if(!(0<=a&&3>=a))return 28;if(0===a)a=Date.now();else if(Tg)a=performance.timeOrigin+performance.now();else return 52;a=Math.round(1E6*a);(u(),F)[c>>>3>>>0]=BigInt(a);return 0}var Ug=[],Vg=(a,b)=>{Ug.length=0;for(var c;c=(u(),x)[a++>>>0];){var d=105!=c;d&=112!=c;b+=d&&b%8?4:0;Ug.push(112==c?(u(),B)[b>>>2>>>0]:106==c?(u(),F)[b>>>3>>>0]:105==c?(u(),A)[b>>>2>>>0]:(u(),E)[b>>>3>>>0]);b+=d?8:4}return Ug};function lc(a,b,c){a>>>=0;b=Vg(b>>>0,c>>>0);return tg[a](...b)}
|
| 60 |
+
function mc(a,b,c){a>>>=0;b=Vg(b>>>0,c>>>0);return tg[a](...b)}var nc=()=>{};function pc(a,b){return t(Zf(a>>>0,b>>>0))}var qc=()=>{L+=1;throw"unwind";};function rc(){return 4294901760}var tc=()=>1,uc=()=>l?require("os").cpus().length:navigator.hardwareConcurrency;
|
| 61 |
+
function vc(a){a>>>=0;var b=(u(),x).length;if(a<=b||4294901760<a)return!1;for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);a:{d=(Math.min(4294901760,65536*Math.ceil(Math.max(a,d)/65536))-v.buffer.byteLength+65535)/65536|0;try{v.grow(d);wa();var e=1;break a}catch(f){}e=void 0}if(e)return!0}return!1}
|
| 62 |
+
var V=a=>{var b=U(a)+1,c=Je(b);T(a,c,b);return c},Wg=(a,b)=>{(u(),B)[a>>>2>>>0]=b;var c=(u(),B)[a>>>2>>>0];(u(),B)[a+4>>>2>>>0]=(b-c)/4294967296},Xg=a=>(u(),B)[a>>>2>>>0]+4294967296*(u(),A)[a+4>>>2>>>0],W=[],Yg=(a,b)=>{W[a>>>0]=b},X=[],Zg=[],$g=(a,b)=>{Zg[a]=new Promise(c=>b.finally(()=>c(a)))},Y=a=>{if(a)return W[a>>>0]},ah=(a,b=0)=>{"unmapped"===a.mapState||Ta();b=re(b);W[b>>>0]=a;return b},bh=(a,b=0)=>{var c=te(b);b=se(b,c);W[c>>>0]=a.queue;W[b>>>0]=a;return b},ch=(a,b)=>{for(a=(u(),B)[a>>>2>>>
|
| 63 |
+
0];a;a=(u(),B)[a>>>2>>>0]){var c=(u(),A)[a+4>>>2>>>0];b[c](a)}},dh=(a,b,c)=>{(u(),B)[a>>>2>>>0]=b;(u(),B)[a+4>>>2>>>0]=c},eh=a=>{var b=(u(),B)[a>>>2>>>0];a=(u(),B)[a+4>>>2>>>0];return Zf(b,a)},Z=a=>{var b=(u(),B)[a>>>2>>>0];a=(u(),B)[a+4>>>2>>>0];if(b)return Zf(b,a);if(0===a)return""},fh=a=>{var b=Z(a+4);var c=(c=(u(),B)[a+12>>>2>>>0])?Y(c):"auto";if(a+=16){var d=Y((u(),B)[a+4>>>2>>>0]);var e=(u(),B)[a+16>>>2>>>0];var f=(u(),B)[a+20>>>2>>>0];if(e){for(var h={},k=0;k<e;++k){var m=f+24*k,p=eh(m+4);
|
| 64 |
+
h[p]=(u(),E)[m+16>>>3>>>0]}e=h}else e=void 0;a={module:d,constants:e,entryPoint:Z(a+8)}}else a=void 0;return{label:b,layout:c,compute:a}},gh=(a,b)=>{function c(d,e){d=a[d];(u(),B)[b+e>>>2>>>0]=d}c("maxTextureDimension1D",4);c("maxTextureDimension2D",8);c("maxTextureDimension3D",12);c("maxTextureArrayLayers",16);c("maxBindGroups",20);c("maxBindGroupsPlusVertexBuffers",24);c("maxBindingsPerBindGroup",28);c("maxDynamicUniformBuffersPerPipelineLayout",32);c("maxDynamicStorageBuffersPerPipelineLayout",
|
| 65 |
+
36);c("maxSampledTexturesPerShaderStage",40);c("maxSamplersPerShaderStage",44);c("maxStorageBuffersPerShaderStage",48);c("maxStorageTexturesPerShaderStage",52);c("maxUniformBuffersPerShaderStage",56);c("minUniformBufferOffsetAlignment",80);c("minStorageBufferOffsetAlignment",84);Wg(b+64,a.maxUniformBufferBindingSize);Wg(b+72,a.maxStorageBufferBindingSize);c("maxVertexBuffers",88);Wg(b+96,a.maxBufferSize);c("maxVertexAttributes",104);c("maxVertexBufferArrayStride",108);c("maxInterStageShaderVariables",
|
| 66 |
+
112);c("maxColorAttachments",116);c("maxColorAttachmentBytesPerSample",120);c("maxComputeWorkgroupStorageSize",124);c("maxComputeInvocationsPerWorkgroup",128);c("maxComputeWorkgroupSizeX",132);c("maxComputeWorkgroupSizeY",136);c("maxComputeWorkgroupSizeZ",140);c("maxComputeWorkgroupsPerDimension",144);void 0!==a.Be&&c("maxImmediateSize",148)},hh=[,"validation","out-of-memory","internal"],ih=[,"compatibility","core"],jh={1:"core-features-and-limits",2:"depth-clip-control",3:"depth32float-stencil8",
|
| 67 |
+
4:"texture-compression-bc",5:"texture-compression-bc-sliced-3d",6:"texture-compression-etc2",7:"texture-compression-astc",8:"texture-compression-astc-sliced-3d",9:"timestamp-query",10:"indirect-first-instance",11:"shader-f16",12:"rg11b10ufloat-renderable",13:"bgra8unorm-storage",14:"float32-filterable",15:"float32-blendable",16:"clip-distances",17:"dual-source-blending",18:"subgroups",19:"texture-formats-tier1",20:"texture-formats-tier2",21:"primitive-index",22:"texture-component-swizzle",327692:"chromium-experimental-unorm16-texture-formats",
|
| 68 |
+
327729:"chromium-experimental-multi-draw-indirect"},kh=[,"low-power","high-performance"],lh=[,"occlusion","timestamp"],mh={undefined:1,unknown:1,destroyed:2};
|
| 69 |
+
function wc(a,b,c,d,e,f){b=O(b);c=O(c);d>>>=0;e>>>=0;f>>>=0;var h=Y(a>>>0);a={};if(f){var k=(u(),B)[f+12>>>2>>>0];if(k){var m=(u(),B)[f+16>>>2>>>0];a.requiredFeatures=Array.from((u(),B).subarray(m>>>2>>>0,m+4*k>>>2>>>0),r=>jh[r])}var p=(u(),B)[f+20>>>2>>>0];if(p){var C={};function r(z,D,za=!1){D=p+D;D=(u(),B)[D>>>2>>>0];4294967295==D||za&&0==D||(C[z]=D)}function y(z,D){D=p+D;var za=(u(),B)[D>>>2>>>0],yb=(u(),B)[D+4>>>2>>>0];if(4294967295!=za||4294967295!=yb)C[z]=Xg(D)}r("maxTextureDimension1D",4);
|
| 70 |
+
r("maxTextureDimension2D",8);r("maxTextureDimension3D",12);r("maxTextureArrayLayers",16);r("maxBindGroups",20);r("maxBindGroupsPlusVertexBuffers",24);r("maxDynamicUniformBuffersPerPipelineLayout",32);r("maxDynamicStorageBuffersPerPipelineLayout",36);r("maxSampledTexturesPerShaderStage",40);r("maxSamplersPerShaderStage",44);r("maxStorageBuffersPerShaderStage",48);r("maxStorageTexturesPerShaderStage",52);r("maxUniformBuffersPerShaderStage",56);r("minUniformBufferOffsetAlignment",80);r("minStorageBufferOffsetAlignment",
|
| 71 |
+
84);y("maxUniformBufferBindingSize",64);y("maxStorageBufferBindingSize",72);r("maxVertexBuffers",88);y("maxBufferSize",96);r("maxVertexAttributes",104);r("maxVertexBufferArrayStride",108);r("maxInterStageShaderVariables",112);r("maxColorAttachments",116);r("maxColorAttachmentBytesPerSample",120);r("maxComputeWorkgroupStorageSize",124);r("maxComputeInvocationsPerWorkgroup",128);r("maxComputeWorkgroupSizeX",132);r("maxComputeWorkgroupSizeY",136);r("maxComputeWorkgroupSizeZ",140);r("maxComputeWorkgroupsPerDimension",
|
| 72 |
+
144);r("maxImmediateSize",148,!0);a.requiredLimits=C}if(k=(u(),B)[f+24>>>2>>>0])k={label:Z(k+4)},a.defaultQueue=k;a.label=Z(f+4)}L+=1;$g(b,h.requestDevice(a).then(r=>{--L;N(()=>{W[e>>>0]=r.queue;W[d>>>0]=r;L+=1;$g(c,r.lost.then(y=>{N(()=>{r.onuncapturederror=()=>{};var z=K(),D=V(y.message);ve(c,mh[y.reason],D);J(z)});--L}));r.onuncapturederror=y=>{var z=5;y.error instanceof GPUValidationError?z=2:y.error instanceof GPUOutOfMemoryError?z=3:y.error instanceof GPUInternalError&&(z=4);var D=K();y=V(y.error.message);
|
| 73 |
+
Ae(d,z,y);J(D)};"adapterInfo"in r||(r.adapterInfo=h.info);ze(b,1,d,0)})},r=>{--L;N(()=>{var y=K(),z=V(r.message);ze(b,3,d,z);c&&ve(c,4,z);J(y)})}))}function xc(a){a>>>=0;var b=Y(a),c=X[a];if(c){for(var d=0;d<c.length;++d)c[d]();delete X[a]}b.destroy()}function yc(a,b,c){a>>>=0;c>>>=0;var d=Y(a);4294967295==c&&(c=void 0);try{var e=d.getMappedRange(b>>>0,c)}catch(h){return 0}var f=Ge(16,e.byteLength);(u(),x).set(new Uint8Array(e),f>>>0);X[a].push(()=>H(f));return f}
|
| 74 |
+
function zc(a,b,c){a>>>=0;c>>>=0;var d=Y(a);4294967295==c&&(c=void 0);try{var e=d.getMappedRange(b>>>0,c)}catch(h){return 0}var f=Ge(16,e.byteLength);(u(),x).fill(0,f,e.byteLength);X[a].push(()=>{(new Uint8Array(e)).set((u(),x).subarray(f>>>0,f+e.byteLength>>>0));H(f)});return f}
|
| 75 |
+
function Ac(a,b,c,d,e){a>>>=0;b=O(b);c=O(c);e>>>=0;var f=Y(a);X[a]=[];4294967295==e&&(e=void 0);L+=1;$g(b,f.mapAsync(c,d>>>0,e).then(()=>{--L;N(()=>{we(b,1,0)})},h=>{--L;N(()=>{K();var k=V(h.message);we(b,"AbortError"===h.name?4:"OperationError"===h.name?3:0,k);delete X[a]})}))}function Bc(a){a>>>=0;var b=Y(a),c=X[a];if(c){for(var d=0;d<c.length;++d)c[d]();delete X[a];b.unmap()}}function Cc(a){delete W[a>>>0]}
|
| 76 |
+
function Dc(a,b,c){a>>>=0;b>>>=0;c>>>=0;var d=!!(u(),B)[b+32>>>2>>>0];b={label:Z(b+4),usage:(u(),B)[b+16>>>2>>>0],size:Xg(b+24),mappedAtCreation:d};a=Y(a);try{var e=a.createBuffer(b)}catch(f){return!1}W[c>>>0]=e;d&&(X[c]=[]);return!0}function Ec(a,b,c,d){a>>>=0;b=O(b);d>>>=0;c=fh(c>>>0);a=Y(a);L+=1;$g(b,a.createComputePipelineAsync(c).then(e=>{--L;N(()=>{W[d>>>0]=e;ue(b,1,d,0)})},e=>{--L;N(()=>{var f=K(),h=V(e.message);ue(b,"validation"===e.reason?3:"internal"===e.reason?4:0,d,h);J(f)})}))}
|
| 77 |
+
function Fc(a,b,c){a>>>=0;b>>>=0;c>>>=0;var d=(u(),B)[b>>>2>>>0],e=(u(),A)[d+4>>>2>>>0];b={label:Z(b+4),code:""};switch(e){case 2:b.code=eh(d+8)}a=Y(a).createShaderModule(b);W[c>>>0]=a}var Gc=a=>{a=Y(a);a.onuncapturederror=null;a.destroy()};
|
| 78 |
+
function Hc(a,b){b=O(b);a=Y(a>>>0);L+=1;$g(b,a.popErrorScope().then(c=>{--L;N(()=>{var d=5;c?c instanceof GPUValidationError?d=2:c instanceof GPUOutOfMemoryError?d=3:c instanceof GPUInternalError&&(d=4):d=1;var e=K(),f=c?V(c.message):0;xe(b,1,d,f);J(e)})},c=>{--L;N(()=>{var d=K(),e=V(c.message);xe(b,1,5,e);J(d)})}))}
|
| 79 |
+
function Ic(a,b,c,d){b=O(b);c>>>=0;d>>>=0;if(c){var e={featureLevel:ih[(u(),A)[c+4>>>2>>>0]],powerPreference:kh[(u(),A)[c+8>>>2>>>0]],forceFallbackAdapter:!!(u(),B)[c+12>>>2>>>0]};a=(u(),B)[c>>>2>>>0];0!==a&&(u(),e.Fe=!!(u(),B)[a+8>>>2>>>0])}"gpu"in navigator?(L+=1,$g(b,navigator.gpu.requestAdapter(e).then(f=>{--L;N(()=>{if(f)W[d>>>0]=f,ye(b,1,d,0);else{var h=K(),k=V("WebGPU not available on this browser (requestAdapter returned null)");ye(b,3,d,k);J(h)}})},f=>{--L;N(()=>{var h=K(),k=V(f.message);
|
| 80 |
+
ye(b,4,d,k);J(h)})}))):(e=K(),a=V("WebGPU not available on this browser (navigator.gpu is not available)"),ye(b,3,d,a),J(e))}function Jc(a,b,c){a>>>=0;b>>>=0;c>>>=0;return Ig(async()=>{var d=[];if(c){var e=(u(),A)[c>>>2>>>0];d.length=b+1;d[b]=new Promise(k=>setTimeout(k,e,0))}else d.length=b;for(var f=0;f<b;++f){var h=Xg(a+8*f);if(!(h in Zg))return h;d[f]=Zg[h]}d=await Promise.race(d);delete Zg[d];return d})}
|
| 81 |
+
var nh={},ph=()=>{if(!oh){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:(globalThis.navigator?.language??"C").replace("-","_")+".UTF-8",_:fa||"./this.program"},b;for(b in nh)void 0===nh[b]?delete a[b]:a[b]=nh[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);oh=c}return oh},oh;function Kc(a,b){if(n)return M(19,1,a,b);a>>>=0;b>>>=0;var c=0,d=0,e;for(e of ph()){var f=b+c;(u(),B)[a+d>>>2>>>0]=f;c+=T(e,f,Infinity)+1;d+=4}return 0}
|
| 82 |
+
function Lc(a,b){if(n)return M(20,1,a,b);a>>>=0;b>>>=0;var c=ph();(u(),B)[a>>>2>>>0]=c.length;a=0;for(var d of c)a+=U(d)+1;(u(),B)[b>>>2>>>0]=a;return 0}function Nc(a){return n?M(21,1,a):52}function Oc(a,b,c,d){return n?M(22,1,a,b,c,d):52}function Pc(a,b,c,d){return n?M(23,1,a,b,c,d):70}var qh=[null,[],[]];
|
| 83 |
+
function Qc(a,b,c,d){if(n)return M(24,1,a,b,c,d);b>>>=0;c>>>=0;d>>>=0;for(var e=0,f=0;f<c;f++){var h=(u(),B)[b>>>2>>>0],k=(u(),B)[b+4>>>2>>>0];b+=8;for(var m=0;m<k;m++){var p=a,C=(u(),x)[h+m>>>0],r=qh[p];0===C||10===C?((1===p?ra:t)(Yf(r)),r.length=0):r.push(C)}e+=k}(u(),B)[d>>>2>>>0]=e;return 0}function Cd(a){return a>>>0}function Ed(a,b){gh(Y(a>>>0).limits,b>>>0);return 1}function Fd(a,b){return Y(a>>>0).features.has(jh[b])}function Gd(a){return BigInt(Y(a>>>0).size)}
|
| 84 |
+
function Hd(a){return BigInt(Y(a>>>0).usage)}function Id(a,b){a>>>=0;b>>>=0;if(b){var c=Z(b+4);b=(u(),B)[b+12>>>2>>>0];b=0!==b?{querySet:Y((u(),B)[b+4>>>2>>>0]),beginningOfPassWriteIndex:(u(),B)[b+8>>>2>>>0],endOfPassWriteIndex:(u(),B)[b+12>>>2>>>0]}:void 0;c={label:c,timestampWrites:b}}b=Y(a);a=pe(0);c=b.beginComputePass(c);W[a>>>0]=c;return a}function Jd(a,b,c,d){c=O(c);d=O(d);a=Y(a>>>0);-1==d&&(d=void 0);a.clearBuffer(Y(b>>>0),c,d)}
|
| 85 |
+
function Kd(a,b,c,d,e,f){c=O(c);e=O(e);f=O(f);Y(a>>>0).copyBufferToBuffer(Y(b>>>0),c,Y(d>>>0),e,f)}function Ld(a){var b=Y(a>>>0);a=ne(0);b=b.finish();W[a>>>0]=b;return a}function Md(a,b,c,d,e,f){f=O(f);Y(a>>>0).resolveQuerySet(Y(b>>>0),c,d,Y(e>>>0),f)}function Nd(a,b,c,d){Y(a>>>0).dispatchWorkgroups(b,c,d)}function Od(a,b,c){c=O(c);Y(a>>>0).dispatchWorkgroupsIndirect(Y(b>>>0),c)}function Pd(a){Y(a>>>0).end()}
|
| 86 |
+
function Qd(a,b,c,d,e){d>>>=0;e>>>=0;a=Y(a>>>0);c=Y(c>>>0);0==d?a.setBindGroup(b,c):a.setBindGroup(b,c,(u(),B),e>>>2,d)}function Rd(a,b){Y(a>>>0).setPipeline(Y(b>>>0))}function Sd(a,b,c){Y(a>>>0).Ee(Y(b>>>0),c)}function Td(a,b){var c=Y(a>>>0);a=me(0);b=c.getBindGroupLayout(b);W[a>>>0]=b;return a}
|
| 87 |
+
function Ud(a,b){function c(e){var f=(u(),B)[e+8>>>2>>>0],h=(u(),B)[e+32>>>2>>>0],k=(u(),B)[e+36>>>2>>>0],m=0;ch(e,{327681:p=>{m=(u(),B)[p+8>>>2>>>0]}});f?(h=Xg(e+24),-1==h&&(h=void 0),f={buffer:Y(f),offset:Xg(e+16),size:h}):f=Y(h||k||m);return{binding:(u(),B)[e+4>>>2>>>0],resource:f}}a>>>=0;b>>>=0;b={label:Z(b+4),layout:Y((u(),B)[b+12>>>2>>>0]),entries:function(e,f){for(var h=[],k=0;k<e;++k)h.push(c(f+40*k));return h}((u(),B)[b+16>>>2>>>0],(u(),B)[b+20>>>2>>>0])};a=Y(a);var d=le(0);Yg(d,a.createBindGroup(b));
|
| 88 |
+
return d}function Vd(a,b){a>>>=0;b>>>=0;var c;b&&(c={label:Z(b+4)});b=Y(a);a=oe(0);c=b.createCommandEncoder(c);W[a>>>0]=c;return a}function Wd(a,b){a>>>=0;b>>>=0;b={type:lh[(u(),A)[b+12>>>2>>>0]],count:(u(),B)[b+16>>>2>>>0]};var c=Y(a);a=qe(0);b=c.createQuerySet(b);W[a>>>0]=b;return a}
|
| 89 |
+
function Xd(a,b){a=Y(a>>>0).adapterInfo;b>>>=0;(u(),B)[b+52>>>2>>>0]=a.subgroupMinSize;(u(),B)[b+56>>>2>>>0]=a.subgroupMaxSize;var c=a.vendor+a.architecture+a.device+a.description;var d=U(c)+1,e=ie(d);e&&T(c,e,d);c=e;d=U(a.vendor);dh(b+4,c,d);c+=d;d=U(a.architecture);dh(b+12,c,d);c+=d;d=U(a.device);dh(b+20,c,d);dh(b+28,c+d,U(a.description));(u(),A)[b+36>>>2>>>0]=2;a=a.isFallbackAdapter?3:4;(u(),A)[b+40>>>2>>>0]=a;(u(),B)[b+44>>>2>>>0]=0;(u(),B)[b+48>>>2>>>0]=0;return 1}
|
| 90 |
+
var rh={"core-features-and-limits":1,"depth-clip-control":2,"depth32float-stencil8":3,"texture-compression-bc":4,"texture-compression-bc-sliced-3d":5,"texture-compression-etc2":6,"texture-compression-astc":7,"texture-compression-astc-sliced-3d":8,"timestamp-query":9,"indirect-first-instance":10,"shader-f16":11,"rg11b10ufloat-renderable":12,"bgra8unorm-storage":13,"float32-filterable":14,"float32-blendable":15,"clip-distances":16,"dual-source-blending":17,subgroups:18,"texture-formats-tier1":19,"texture-formats-tier2":20,
|
| 91 |
+
"primitive-index":21,"texture-component-swizzle":22,"chromium-experimental-unorm16-texture-formats":327692,"chromium-experimental-multi-draw-indirect":327729};function Yd(a,b){b>>>=0;var c=Y(a>>>0);a=ie(4*c.features.size);var d=0,e=0;for(const f of c.features)c=rh[f],0<=c&&((u(),A)[a+d>>>2>>>0]=c,d+=4,e++);(u(),B)[b+4>>>2>>>0]=a;(u(),B)[b>>>2>>>0]=e}function Zd(a,b){gh(Y(a>>>0).limits,b>>>0);return 1}function $d(a,b){Y(a>>>0).pushErrorScope(hh[b])}
|
| 92 |
+
function ae(a,b,c){b>>>=0;c>>>=0;a=Y(a>>>0);b=Array.from((u(),A).subarray(c>>>2>>>0,c+4*b>>>2>>>0),d=>Y(d));a.submit(b)}function be(a,b,c,d,e){c=O(c);d>>>=0;e>>>=0;a=Y(a>>>0);b=Y(b>>>0);d=(u(),x).subarray(d>>>0,d+e>>>0);a.writeBuffer(b,c,d,0,e)}n||Lf();n||(v=new WebAssembly.Memory({initial:256,maximum:65536,shared:!0}),wa());g.wasmBinary&&(sa=g.wasmBinary);g.stackSave=()=>K();g.stackRestore=a=>J(a);g.stackAlloc=a=>Je(a);
|
| 93 |
+
g.setValue=function(a,b,c="i8"){c.endsWith("*")&&(c="*");switch(c){case "i1":(u(),w)[a>>>0]=b;break;case "i8":(u(),w)[a>>>0]=b;break;case "i16":(u(),Na)[a>>>1>>>0]=b;break;case "i32":(u(),A)[a>>>2>>>0]=b;break;case "i64":(u(),F)[a>>>3>>>0]=BigInt(b);break;case "float":(u(),Pa)[a>>>2>>>0]=b;break;case "double":(u(),E)[a>>>3>>>0]=b;break;case "*":(u(),B)[a>>>2>>>0]=b;break;default:Ta(`invalid type for setValue: ${c}`)}};
|
| 94 |
+
g.getValue=function(a,b="i8"){b.endsWith("*")&&(b="*");switch(b){case "i1":return(u(),w)[a>>>0];case "i8":return(u(),w)[a>>>0];case "i16":return(u(),Na)[a>>>1>>>0];case "i32":return(u(),A)[a>>>2>>>0];case "i64":return(u(),F)[a>>>3>>>0];case "float":return(u(),Pa)[a>>>2>>>0];case "double":return(u(),E)[a>>>3>>>0];case "*":return(u(),B)[a>>>2>>>0];default:Ta(`invalid type for getValue: ${b}`)}};g.UTF8ToString=Zf;g.stringToUTF8=T;g.lengthBytesUTF8=U;
|
| 95 |
+
var ug=[Dd,Kf,Vf,jb,kb,lb,mb,nb,ob,pb,qb,rb,sb,tb,ub,vb,gc,hc,ic,Kc,Lc,Nc,Oc,Pc,Qc],tg={1028716:(a,b,c,d,e)=>{if("undefined"==typeof g||!g.Vc)return 1;a=Zf(Number(a>>>0));a.startsWith("./")&&(a=a.substring(2));a=g.Vc.get(a);if(!a)return 2;b=Number(b>>>0);c=Number(c>>>0);d=Number(d>>>0);if(b+c>a.byteLength)return 3;try{const f=a.subarray(b,b+c);switch(e){case 0:(u(),x).set(f,d>>>0);break;case 1:g.bd?g.bd(d,f):g.pe(d,f);break;default:return 4}return 0}catch{return 4}},1029540:(a,b,c)=>{g.Td(a,(u(),
|
| 96 |
+
x).subarray(b>>>0,b+c>>>0))},1029604:()=>g.ne(),1029646:a=>{g.kd(a)},1029683:()=>"undefined"!==typeof wasmOffsetConverter},fe,Ja,ge,he,H,ie,je,ke,le,me,ne,oe,pe,qe,re,se,te,ue,ve,we,xe,ye,ze,Ae,Ga,Ma,Be,Ce,De,Ee,Fe,Ge,I,He,Ie,J,Je,K,Ke,Le,Me,Ne,dynCall_vii,Oe,dynCall_v,Pe,Qe,Re,dynCall_iii,Se,Te,Ue,dynCall_vi,Ve,We,Xe,Ye,Ze,$e,af,bf,cf,df,ef,ff,gf,hf,jf,kf,lf,mf,nf,of,pf,qf,rf,sf,tf,uf,vf,wf,xf,yf,Za;function Yc(a,b,c,d){var e=K();try{return Ue(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}
|
| 97 |
+
function Xc(a,b,c){var d=K();try{return dynCall_iii(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0)}}function nd(a){var b=K();try{dynCall_v(a)}catch(c){J(b);if(c!==c+0)throw c;I(1,0)}}function Wc(a,b){var c=K();try{return Oe(a,b)}catch(d){J(c);if(d!==d+0)throw d;I(1,0)}}function pd(a,b,c){var d=K();try{dynCall_vii(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0)}}function od(a,b){var c=K();try{dynCall_vi(a,b)}catch(d){J(c);if(d!==d+0)throw d;I(1,0)}}
|
| 98 |
+
function bd(a,b,c,d,e,f,h){var k=K();try{return Re(a,b,c,d,e,f,h)}catch(m){J(k);if(m!==m+0)throw m;I(1,0)}}function td(a,b,c,d,e,f){var h=K();try{Pe(a,b,c,d,e,f)}catch(k){J(h);if(k!==k+0)throw k;I(1,0)}}function rd(a,b,c,d){var e=K();try{Te(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}function ud(a,b,c,d,e,f,h){var k=K();try{We(a,b,c,d,e,f,h)}catch(m){J(k);if(m!==m+0)throw m;I(1,0)}}function Ad(a,b,c,d,e,f,h){var k=K();try{Xe(a,b,c,d,e,f,h)}catch(m){J(k);if(m!==m+0)throw m;I(1,0)}}
|
| 99 |
+
function zd(a,b,c,d,e,f,h,k){var m=K();try{ff(a,b,c,d,e,f,h,k)}catch(p){J(m);if(p!==p+0)throw p;I(1,0)}}function xd(a,b,c,d,e,f,h,k,m,p,C,r){var y=K();try{Ye(a,b,c,d,e,f,h,k,m,p,C,r)}catch(z){J(y);if(z!==z+0)throw z;I(1,0)}}function Zc(a,b,c,d,e){var f=K();try{return Ve(a,b,c,d,e)}catch(h){J(f);if(h!==h+0)throw h;I(1,0)}}function Bd(a,b,c,d,e,f){var h=K();try{gf(a,b,c,d,e,f)}catch(k){J(h);if(k!==k+0)throw k;I(1,0)}}
|
| 100 |
+
function sd(a,b,c,d,e){var f=K();try{Qe(a,b,c,d,e)}catch(h){J(f);if(h!==h+0)throw h;I(1,0)}}function vd(a,b,c,d,e,f,h,k){var m=K();try{Se(a,b,c,d,e,f,h,k)}catch(p){J(m);if(p!==p+0)throw p;I(1,0)}}function Vc(a){var b=K();try{return hf(a)}catch(c){J(b);if(c!==c+0)throw c;I(1,0)}}function hd(a,b,c){var d=K();try{return jf(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0)}}function kd(a,b){var c=K();try{return uf(a,b)}catch(d){J(c);if(d!==d+0)throw d;I(1,0);return 0n}}
|
| 101 |
+
function jd(a){var b=K();try{return Ze(a)}catch(c){J(b);if(c!==c+0)throw c;I(1,0);return 0n}}function gd(a,b,c,d){var e=K();try{return kf(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}function fd(a,b,c,d,e){var f=K();try{return lf(a,b,c,d,e)}catch(h){J(f);if(h!==h+0)throw h;I(1,0)}}function ed(a,b,c,d,e,f){var h=K();try{return mf(a,b,c,d,e,f)}catch(k){J(h);if(k!==k+0)throw k;I(1,0)}}function ad(a,b,c,d,e,f){var h=K();try{return df(a,b,c,d,e,f)}catch(k){J(h);if(k!==k+0)throw k;I(1,0)}}
|
| 102 |
+
function $c(a,b,c,d,e,f){var h=K();try{return nf(a,b,c,d,e,f)}catch(k){J(h);if(k!==k+0)throw k;I(1,0)}}function cd(a,b,c,d,e,f,h,k){var m=K();try{return ef(a,b,c,d,e,f,h,k)}catch(p){J(m);if(p!==p+0)throw p;I(1,0)}}function md(a,b,c,d,e){var f=K();try{return of(a,b,c,d,e)}catch(h){J(f);if(h!==h+0)throw h;I(1,0);return 0n}}function Uc(a,b,c,d){var e=K();try{return pf(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}
|
| 103 |
+
function Sc(a,b,c,d){var e=K();try{return qf(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}function dd(a,b,c,d,e,f,h,k,m,p,C,r){var y=K();try{return rf(a,b,c,d,e,f,h,k,m,p,C,r)}catch(z){J(y);if(z!==z+0)throw z;I(1,0)}}function wd(a,b,c,d,e,f,h,k,m,p,C){var r=K();try{sf(a,b,c,d,e,f,h,k,m,p,C)}catch(y){J(r);if(y!==y+0)throw y;I(1,0)}}function yd(a,b,c,d,e,f,h,k,m,p,C,r,y,z,D,za){var yb=K();try{tf(a,b,c,d,e,f,h,k,m,p,C,r,y,z,D,za)}catch(Bb){J(yb);if(Bb!==Bb+0)throw Bb;I(1,0)}}
|
| 104 |
+
function ld(a,b,c){var d=K();try{return af(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0);return 0n}}function Tc(a,b,c){var d=K();try{return $e(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0)}}function Rc(a,b,c){var d=K();try{return bf(a,b,c)}catch(e){J(d);if(e!==e+0)throw e;I(1,0)}}function qd(a,b,c,d){var e=K();try{cf(a,b,c,d)}catch(f){J(e);if(f!==f+0)throw f;I(1,0)}}
|
| 105 |
+
function de(){var a=G;a=Object.assign({},a);var b=d=>e=>d(e)>>>0,c=d=>()=>d()>>>0;a.ac=b(a.ac);a.Dc=c(a.Dc);a.Fc=b(a.Fc);a.sd=(d=>(e,f)=>d(e,f)>>>0)(a.sd);a.xd=b(a.xd);a.yd=c(a.yd);a.Cd=b(a.Cd);return a}function Ea(){if(0<Cf)Df=Ea;else if(n)xa?.(g),Sa();else{for(var a=Bf;0<a.length;)a.shift()(g);0<Cf?Df=Ea:(g.calledRun=!0,ua||(Sa(),xa?.(g)))}}var G;n||(G=await (Da()),Ea());g.PTR_SIZE=4;
|
| 106 |
+
g.webgpuInit=a=>{const b=new WeakMap;let c=1,d=void 0,e=void 0;g.webgpuRegisterDevice=k=>{if(void 0!==e)throw Error("another WebGPU EP inference session is being created.");if(k){var m=b.get(k);if(!m){m=ke(0);const p=bh(k,m);m=[c++,m,p];b.set(k,m)}d=k;e=m[0];return m}d=void 0;e=0};const f=new Map;g.webgpuOnCreateSession=k=>{if(void 0!==e){var m=e;e=void 0;if(k){const p=ge(m);f.set(k,p);0===m&&a(d??Y(p))}d=void 0}};g.webgpuOnReleaseSession=k=>{f.delete(k)};const h=Symbol("gpuBufferMetadata");g.webgpuRegisterBuffer=
|
| 107 |
+
(k,m,p)=>{if(p)return k[h]=[p,NaN],p;if(p=k[h])return p[1]++,p[0];m=f.get(m);if(void 0===m)throw Error("Invalid session handle passed to webgpuRegisterBuffer");m=ah(k,m);k[h]=[m,1];return m};g.webgpuUnregisterBuffer=k=>{const m=k[h];if(!m)throw Error("Buffer is not registered");m[1]--;0===m[1]&&(je(m[0]),delete k[h])};g.webgpuGetBuffer=k=>Y(k);g.webgpuCreateDownloader=(k,m,p)=>{p=f.get(p);if(void 0===p)throw Error("Invalid session handle passed to webgpuRegisterBuffer");const C=Y(p),r=16*Math.ceil(Number(m)/
|
| 108 |
+
16);return async()=>{const y=C.createBuffer({size:r,usage:9});try{const z=C.createCommandEncoder();z.copyBufferToBuffer(k,0,y,0,r);C.queue.submit([z.finish()]);await y.mapAsync(GPUMapMode.READ);return y.getMappedRange().slice(0,m)}finally{y.destroy()}}};g.bd=(k,m)=>{var p=m.buffer;const C=m.byteOffset,r=m.byteLength;m=16*Math.ceil(Number(r)/16);k=Y(k);if(!d){var y=ge(e);d=Y(y)}y=d.createBuffer({mappedAtCreation:!0,size:m,usage:6});const z=y.getMappedRange();(new Uint8Array(z)).set(new Uint8Array(p,
|
| 109 |
+
C,r));y.unmap();p=d.createCommandEncoder();p.copyBufferToBuffer(y,0,k,0,m);d.queue.submit([p.finish()]);y.destroy()}};
|
| 110 |
+
g.webnnInit=a=>{const b=a[0];[g.ne,g.kd,g.webnnEnsureTensor,g.Td,g.webnnDownloadTensor,g.me,g.webnnEnableTraceEvent]=a.slice(1);g.webnnReleaseTensorId=g.kd;g.webnnUploadTensor=g.Td;g.webnnRegisterMLContext=g.me;g.webnnOnRunStart=c=>b.onRunStart(c);g.webnnOnRunEnd=b.onRunEnd.bind(b);g.webnnOnReleaseSession=c=>{b.onReleaseSession(c)};g.webnnCreateMLTensorDownloader=(c,d)=>b.createMLTensorDownloader(c,d);g.webnnRegisterMLTensor=(c,d,e,f)=>b.registerMLTensor(c,d,e,f);g.webnnCreateMLContext=c=>b.createMLContext(c);
|
| 111 |
+
g.webnnRegisterMLConstant=(c,d,e,f,h,k)=>b.registerMLConstant(c,d,e,f,h,g.Vc,k);g.webnnRegisterGraphInput=b.registerGraphInput.bind(b);g.webnnIsGraphInput=b.isGraphInput.bind(b);g.webnnRegisterGraphOutput=b.registerGraphOutput.bind(b);g.webnnIsGraphOutput=b.isGraphOutput.bind(b);g.webnnCreateTemporaryTensor=b.createTemporaryTensor.bind(b);g.webnnIsGraphInputOutputTypeSupported=b.isGraphInputOutputTypeSupported.bind(b)};Ra?moduleRtn=g:moduleRtn=new Promise((a,b)=>{xa=a;ya=b});
|
| 112 |
+
;return moduleRtn}export default ortWasmThreaded;var isPthread=globalThis.self?.name?.startsWith("em-pthread");var isNode=globalThis.process?.versions?.node&&globalThis.process?.type!="renderer";if(isNode)isPthread=(await import("worker_threads")).workerData==="em-pthread";isPthread&&ortWasmThreaded();
|
runtime/vendor/ort-wasm-simd-threaded.asyncify.wasm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7e83cd6cee77e478bc96a7e91b198144fb5e4126287daf1f9b54bb195ebcd55a
|
| 3 |
+
size 24254953
|
runtime/vendor/ort.webgpu.mjs
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
runtime/vendor/transformers.web.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c7dc553ba83607a7d3cde4782e4055fcd15cb228f8f1cdc3fc149b1094580592
|
| 3 |
+
size 10548223
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": null,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": "<s>",
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eos_token": "</s>",
|
| 7 |
+
"is_local": true,
|
| 8 |
+
"legacy": true,
|
| 9 |
+
"local_files_only": true,
|
| 10 |
+
"model_max_length": 131072,
|
| 11 |
+
"pad_token": "</s>",
|
| 12 |
+
"sp_model_kwargs": {},
|
| 13 |
+
"spaces_between_special_tokens": false,
|
| 14 |
+
"tokenizer_class": "TokenizersBackend",
|
| 15 |
+
"unk_token": "<unk>",
|
| 16 |
+
"use_default_system_prompt": false,
|
| 17 |
+
"chat_template": "{{- bos_token }}{%- if tools %}\n {%- set tool_definitions %}\n {{- \"# Tools\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson(ensure_ascii=False) }}\n {%- endfor %}\n {{- '\\n</tools>\\n\\nTool usage guidelines:\\n- You may call zero or more functions. If no function calls are needed, just answer normally and do not include any <function ... </function>.\\n- When calling a function, return an XML object within <function ... </function> using:\\n<function name=\"function-name\"><param name=\"param-name\">param-value</param></function>\\n- param-value may be multi-line. If it contains <, & or newline characters, wrap it in a CDATA block: <param name=\"param-name\"><![CDATA[...multi-line value...]]></param>' }}\n {%- endset %}\n \n {{- '<|im_start|>system\\n' }}\n {%- if messages[0].role == 'system' %}\n {%- if '<tool_def_sep>' in messages[0].content %}\n {{- messages[0].content.replace('<tool_def_sep>', tool_definitions) }}\n {%- else %}\n {{- messages[0].content + '\\n\\n' + tool_definitions }}\n {%- endif %}\n {%- else %}\n {{- tool_definitions.lstrip() }}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n {%- if message.content is string %}\n {%- set content = message.content %}\n {%- else %}\n {%- set content = '' %}\n {%- endif %}\n {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- else %}\n {%- if '</think>' in content %}\n {%- set reasoning_content = content.split('</think>')[0].rstrip('\\n').split('<think>')[-1].lstrip('\\n') %}\n {%- set content = content.split('</think>')[-1].lstrip('\\n') %}\n {%- endif %}\n {%- endif %}\n \n {%- if message.tool_calls %}\n {%- set content_parts = content.split('<tool_sep>') %}\n {%- set processed_content = content_parts[0] %}\n {%- set tool_calls_count = message.tool_calls|length %}\n {%- set tool_sep_count = content_parts|length - 1 %}\n \n {%- for i in range(1, content_parts|length) %}\n {%- set tool_index = i - 1 %}\n {%- if tool_index < tool_calls_count %}\n {%- set tool_call = message.tool_calls[tool_index] %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- set single_tool_xml %}\n {{- '<function name=\"' ~ tool_call.name ~ '\">' }}\n {%- if tool_call.arguments %}\n {%- set args_dict = tool_call.arguments %}\n {%- for param_name, param_value in args_dict.items() %}\n {{- '<param name=\"' ~ param_name ~ '\">' }}\n {%- if param_value is string and ('<' in param_value or '&' in param_value or '\\n' in param_value) %}\n {{- '<![CDATA[' + param_value + ']]>' }}\n {%- else %}\n {{- param_value }}\n {%- endif %}\n {{- '</param>' }}\n {%- endfor %}\n {%- endif %}\n {{- '</function>' }}\n {%- endset %}\n {%- set processed_content = processed_content + single_tool_xml + content_parts[i] %}\n {%- else %}\n {%- set processed_content = processed_content + content_parts[i] %}\n {%- endif %}\n {%- endfor %}\n \n {%- if tool_calls_count > tool_sep_count %}\n {%- for remaining_index in range(tool_sep_count, tool_calls_count) %}\n {%- set tool_call = message.tool_calls[remaining_index] %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- set remaining_tool_xml %}\n {{- '<function name=\"' ~ tool_call.name ~ '\">' }}\n {%- if tool_call.arguments %}\n {%- set args_dict = tool_call.arguments %}\n {%- for param_name, param_value in args_dict.items() %}\n {{- '<param name=\"' ~ param_name ~ '\">' }}\n {%- if param_value is string and ('<' in param_value or '&' in param_value or '\\n' in param_value) %}\n {{- '<![CDATA[' + param_value + ']]>' }}\n {%- else %}\n {{- param_value }}\n {%- endif %}\n {{- '</param>' }}\n {%- endfor %}\n {%- endif %}\n {{- '</function>' }}\n {%- endset %}\n {%- set processed_content = processed_content + remaining_tool_xml %}\n {%- endfor %}\n {%- endif %}\n \n {%- set content = processed_content %}\n {%- endif %}\n \n {%- if reasoning_content %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content.strip('\\n') + '\\n</think>\\n\\n' + content.lstrip('\\n') }}\n {%- elif '<think>' not in content and '</think>' not in content %}\n {{- '<|im_start|>' + message.role + '\\n<think>\\n\\n</think>\\n\\n' + content.lstrip('\\n') }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n \n {%- if message.tool_calls and not has_tool_sep %}\n {%- for tool_call in message.tool_calls %}\n {%- if (loop.first and content) or (not loop.first) %}\n {{- '\\n' }}\n {%- endif %}\n {%- if tool_call.function %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '<function name=\"' ~ tool_call.name ~ '\">' }}\n {%- if tool_call.arguments %}\n {%- set args_dict = tool_call.arguments %}\n {%- for param_name, param_value in args_dict.items() %}\n {{- '<param name=\"' ~ param_name ~ '\">' }}\n {%- if param_value is string and ('<' in param_value or '&' in param_value or '\\n' in param_value) %}\n {{- '<![CDATA[' + param_value + ']]>' }}\n {%- else %}\n {{- param_value }}\n {%- endif %}\n {{- '</param>' }}\n {%- endfor %}\n {%- endif %}\n {{- '</function>' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {%- if message.content is string %}\n {{- content }}\n {%- else %}\n {{- message.content | tojson(ensure_ascii=False) }}\n {%- endif %}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if enable_thinking is defined %}\n {%- if enable_thinking is false %}\n {{- '<think>\\n\\n</think>\\n\\n' }}\n {%- elif enable_thinking is true %}\n {{- '<think>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endif %}\n"
|
| 18 |
+
}
|
validation/cold-cache-results.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"status": "passed",
|
| 3 |
+
"modelNetworkDisabled": true,
|
| 4 |
+
"nativeToolCallExact": true,
|
| 5 |
+
"coldBrowserRestart": true,
|
| 6 |
+
"cacheBytes": 1879921408,
|
| 7 |
+
"browser": "150.0.7871.187",
|
| 8 |
+
"cases": [
|
| 9 |
+
{
|
| 10 |
+
"case": "single_address",
|
| 11 |
+
"contentSha256": "6fb7d867dc3ffc68a48c3d8ba62326085e54207791b1fe596ed1ccefe57520ce",
|
| 12 |
+
"unchanged": true
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"case": "escaped_address",
|
| 16 |
+
"contentSha256": "bbca493756a904976f235188b871396fe327e0257118ca15b9a428b06fb30e52",
|
| 17 |
+
"unchanged": true
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"case": "typed_labels",
|
| 21 |
+
"contentSha256": "400631740d1f4d911f6fb52e748a92e2700e4cbda20e7aae7c2a68f39530dcbb",
|
| 22 |
+
"unchanged": true
|
| 23 |
+
}
|
| 24 |
+
],
|
| 25 |
+
"harnessSha256": "140c191d0f0b9cd50a6376deb2ca8e0042340a3f964915e192cff91f2fbef652",
|
| 26 |
+
"readySha256": "659375dbc84327f36a0de545aa1f769771f386a01e4a4d083707f9261530f395",
|
| 27 |
+
"eventsSha256": "6ed824b7f684f4f154b08805b2a191bfb66d0eccd7a91c54bfdb43874faa91d7",
|
| 28 |
+
"time": 1789231468.5665188
|
| 29 |
+
}
|
validation/context-results.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"status": "passed",
|
| 3 |
+
"contextWindowExercised": 16384,
|
| 4 |
+
"results": [
|
| 5 |
+
{
|
| 6 |
+
"inputTokens": 4088,
|
| 7 |
+
"generatedTokens": 8,
|
| 8 |
+
"finite": true,
|
| 9 |
+
"seconds": 1.199800000190735
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"inputTokens": 8184,
|
| 13 |
+
"generatedTokens": 8,
|
| 14 |
+
"finite": true,
|
| 15 |
+
"seconds": 2.257800000190735
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"inputTokens": 16376,
|
| 19 |
+
"generatedTokens": 8,
|
| 20 |
+
"finite": true,
|
| 21 |
+
"seconds": 5.950199999809265
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"inputTokens": 16383,
|
| 25 |
+
"generatedTokens": 1,
|
| 26 |
+
"finite": true,
|
| 27 |
+
"seconds": 5.6705
|
| 28 |
+
}
|
| 29 |
+
],
|
| 30 |
+
"implementationSha256": "6502ce8d72aa9f9a68d9fa8aa646543d1d6bcfa089db92658e4da3af3c2abd80"
|
| 31 |
+
}
|
validation/numerical-results.json
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"passed": true,
|
| 3 |
+
"checks": [
|
| 4 |
+
{
|
| 5 |
+
"case": "single_address",
|
| 6 |
+
"step": 0,
|
| 7 |
+
"sourceBf16ToFp16": {
|
| 8 |
+
"maxAbs": 0.248046875,
|
| 9 |
+
"relativeRms": 0.012782927668845466,
|
| 10 |
+
"cosine": 0.9999188460342593,
|
| 11 |
+
"top1Equal": true,
|
| 12 |
+
"finite": true
|
| 13 |
+
},
|
| 14 |
+
"fp16ToGptq": {
|
| 15 |
+
"maxAbs": 2.92236328125,
|
| 16 |
+
"relativeRms": 0.1725033061543679,
|
| 17 |
+
"cosine": 0.9851563643330277,
|
| 18 |
+
"top1Equal": true,
|
| 19 |
+
"finite": true
|
| 20 |
+
},
|
| 21 |
+
"gptqToWebgpu": {
|
| 22 |
+
"maxAbs": 0.0673828125,
|
| 23 |
+
"relativeRms": 0.0042797916585819926,
|
| 24 |
+
"cosine": 0.9999915840946518,
|
| 25 |
+
"top1Equal": true,
|
| 26 |
+
"finite": true
|
| 27 |
+
},
|
| 28 |
+
"passed": true
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"case": "single_address",
|
| 32 |
+
"step": 1,
|
| 33 |
+
"sourceBf16ToFp16": {
|
| 34 |
+
"maxAbs": 0.392578125,
|
| 35 |
+
"relativeRms": 0.03175030043037405,
|
| 36 |
+
"cosine": 0.9995014526875671,
|
| 37 |
+
"top1Equal": true,
|
| 38 |
+
"finite": true
|
| 39 |
+
},
|
| 40 |
+
"fp16ToGptq": {
|
| 41 |
+
"maxAbs": 5.8984375,
|
| 42 |
+
"relativeRms": 0.4321884810039682,
|
| 43 |
+
"cosine": 0.9178090500009005,
|
| 44 |
+
"top1Equal": true,
|
| 45 |
+
"finite": true
|
| 46 |
+
},
|
| 47 |
+
"gptqToWebgpu": {
|
| 48 |
+
"maxAbs": 0.1185302734375,
|
| 49 |
+
"relativeRms": 0.009224104859662774,
|
| 50 |
+
"cosine": 0.9999598279641384,
|
| 51 |
+
"top1Equal": true,
|
| 52 |
+
"finite": true
|
| 53 |
+
},
|
| 54 |
+
"passed": true
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"case": "single_address",
|
| 58 |
+
"step": 2,
|
| 59 |
+
"sourceBf16ToFp16": {
|
| 60 |
+
"maxAbs": 0.40625,
|
| 61 |
+
"relativeRms": 0.024433671533829995,
|
| 62 |
+
"cosine": 0.9998189972088237,
|
| 63 |
+
"top1Equal": true,
|
| 64 |
+
"finite": true
|
| 65 |
+
},
|
| 66 |
+
"fp16ToGptq": {
|
| 67 |
+
"maxAbs": 4.21875,
|
| 68 |
+
"relativeRms": 0.15488227828082832,
|
| 69 |
+
"cosine": 0.9880322921705068,
|
| 70 |
+
"top1Equal": true,
|
| 71 |
+
"finite": true
|
| 72 |
+
},
|
| 73 |
+
"gptqToWebgpu": {
|
| 74 |
+
"maxAbs": 0.125,
|
| 75 |
+
"relativeRms": 0.00558969882051299,
|
| 76 |
+
"cosine": 0.9999846162524721,
|
| 77 |
+
"top1Equal": true,
|
| 78 |
+
"finite": true
|
| 79 |
+
},
|
| 80 |
+
"passed": true
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"case": "single_address",
|
| 84 |
+
"step": 3,
|
| 85 |
+
"sourceBf16ToFp16": {
|
| 86 |
+
"maxAbs": 0.244140625,
|
| 87 |
+
"relativeRms": 0.02230636952290329,
|
| 88 |
+
"cosine": 0.9997514739004472,
|
| 89 |
+
"top1Equal": true,
|
| 90 |
+
"finite": true
|
| 91 |
+
},
|
| 92 |
+
"fp16ToGptq": {
|
| 93 |
+
"maxAbs": 2.0703125,
|
| 94 |
+
"relativeRms": 0.15789749529090216,
|
| 95 |
+
"cosine": 0.9876037120121298,
|
| 96 |
+
"top1Equal": true,
|
| 97 |
+
"finite": true
|
| 98 |
+
},
|
| 99 |
+
"gptqToWebgpu": {
|
| 100 |
+
"maxAbs": 0.0888671875,
|
| 101 |
+
"relativeRms": 0.00605211109920661,
|
| 102 |
+
"cosine": 0.9999817012220191,
|
| 103 |
+
"top1Equal": true,
|
| 104 |
+
"finite": true
|
| 105 |
+
},
|
| 106 |
+
"passed": true
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"case": "typed_labels",
|
| 110 |
+
"step": 0,
|
| 111 |
+
"sourceBf16ToFp16": {
|
| 112 |
+
"maxAbs": 0.38671875,
|
| 113 |
+
"relativeRms": 0.025063363075193648,
|
| 114 |
+
"cosine": 0.9997845808098521,
|
| 115 |
+
"top1Equal": true,
|
| 116 |
+
"finite": true
|
| 117 |
+
},
|
| 118 |
+
"fp16ToGptq": {
|
| 119 |
+
"maxAbs": 2.6171875,
|
| 120 |
+
"relativeRms": 0.1662042144350609,
|
| 121 |
+
"cosine": 0.9868052467412282,
|
| 122 |
+
"top1Equal": true,
|
| 123 |
+
"finite": true
|
| 124 |
+
},
|
| 125 |
+
"gptqToWebgpu": {
|
| 126 |
+
"maxAbs": 0.078125,
|
| 127 |
+
"relativeRms": 0.005452968305617882,
|
| 128 |
+
"cosine": 0.9999875200694265,
|
| 129 |
+
"top1Equal": true,
|
| 130 |
+
"finite": true
|
| 131 |
+
},
|
| 132 |
+
"passed": true
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"case": "typed_labels",
|
| 136 |
+
"step": 1,
|
| 137 |
+
"sourceBf16ToFp16": {
|
| 138 |
+
"maxAbs": 0.380859375,
|
| 139 |
+
"relativeRms": 0.0250109210315334,
|
| 140 |
+
"cosine": 0.9997064286834567,
|
| 141 |
+
"top1Equal": true,
|
| 142 |
+
"finite": true
|
| 143 |
+
},
|
| 144 |
+
"fp16ToGptq": {
|
| 145 |
+
"maxAbs": 7.640625,
|
| 146 |
+
"relativeRms": 0.57221657649197,
|
| 147 |
+
"cosine": 0.8201217343475685,
|
| 148 |
+
"top1Equal": true,
|
| 149 |
+
"finite": true
|
| 150 |
+
},
|
| 151 |
+
"gptqToWebgpu": {
|
| 152 |
+
"maxAbs": 0.212890625,
|
| 153 |
+
"relativeRms": 0.018333812515897996,
|
| 154 |
+
"cosine": 0.999833960131897,
|
| 155 |
+
"top1Equal": true,
|
| 156 |
+
"finite": true
|
| 157 |
+
},
|
| 158 |
+
"passed": true
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"case": "typed_labels",
|
| 162 |
+
"step": 2,
|
| 163 |
+
"sourceBf16ToFp16": {
|
| 164 |
+
"maxAbs": 0.345703125,
|
| 165 |
+
"relativeRms": 0.018745048201074564,
|
| 166 |
+
"cosine": 0.9998726263349046,
|
| 167 |
+
"top1Equal": true,
|
| 168 |
+
"finite": true
|
| 169 |
+
},
|
| 170 |
+
"fp16ToGptq": {
|
| 171 |
+
"maxAbs": 4.439453125,
|
| 172 |
+
"relativeRms": 0.19829943940799244,
|
| 173 |
+
"cosine": 0.9824647962089508,
|
| 174 |
+
"top1Equal": true,
|
| 175 |
+
"finite": true
|
| 176 |
+
},
|
| 177 |
+
"gptqToWebgpu": {
|
| 178 |
+
"maxAbs": 0.1796875,
|
| 179 |
+
"relativeRms": 0.006915722281827882,
|
| 180 |
+
"cosine": 0.9999793827494786,
|
| 181 |
+
"top1Equal": true,
|
| 182 |
+
"finite": true
|
| 183 |
+
},
|
| 184 |
+
"passed": true
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"case": "typed_labels",
|
| 188 |
+
"step": 3,
|
| 189 |
+
"sourceBf16ToFp16": {
|
| 190 |
+
"maxAbs": 0.234375,
|
| 191 |
+
"relativeRms": 0.018754406808742356,
|
| 192 |
+
"cosine": 0.999827896719525,
|
| 193 |
+
"top1Equal": true,
|
| 194 |
+
"finite": true
|
| 195 |
+
},
|
| 196 |
+
"fp16ToGptq": {
|
| 197 |
+
"maxAbs": 2.617431640625,
|
| 198 |
+
"relativeRms": 0.186232702205544,
|
| 199 |
+
"cosine": 0.9827491247292427,
|
| 200 |
+
"top1Equal": true,
|
| 201 |
+
"finite": true
|
| 202 |
+
},
|
| 203 |
+
"gptqToWebgpu": {
|
| 204 |
+
"maxAbs": 0.076171875,
|
| 205 |
+
"relativeRms": 0.005799131539776698,
|
| 206 |
+
"cosine": 0.9999832046335031,
|
| 207 |
+
"top1Equal": true,
|
| 208 |
+
"finite": true
|
| 209 |
+
},
|
| 210 |
+
"passed": true
|
| 211 |
+
},
|
| 212 |
+
{
|
| 213 |
+
"case": "tool_history",
|
| 214 |
+
"step": 0,
|
| 215 |
+
"sourceBf16ToFp16": {
|
| 216 |
+
"maxAbs": 0.1943359375,
|
| 217 |
+
"relativeRms": 0.011942814015739078,
|
| 218 |
+
"cosine": 0.9999351512834989,
|
| 219 |
+
"top1Equal": true,
|
| 220 |
+
"finite": true
|
| 221 |
+
},
|
| 222 |
+
"fp16ToGptq": {
|
| 223 |
+
"maxAbs": 3.724609375,
|
| 224 |
+
"relativeRms": 0.1542023887030577,
|
| 225 |
+
"cosine": 0.9880457221982332,
|
| 226 |
+
"top1Equal": true,
|
| 227 |
+
"finite": true
|
| 228 |
+
},
|
| 229 |
+
"gptqToWebgpu": {
|
| 230 |
+
"maxAbs": 0.07421875,
|
| 231 |
+
"relativeRms": 0.004467858699488606,
|
| 232 |
+
"cosine": 0.9999902288828103,
|
| 233 |
+
"top1Equal": true,
|
| 234 |
+
"finite": true
|
| 235 |
+
},
|
| 236 |
+
"passed": true
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"case": "tool_history",
|
| 240 |
+
"step": 1,
|
| 241 |
+
"sourceBf16ToFp16": {
|
| 242 |
+
"maxAbs": 0.55859375,
|
| 243 |
+
"relativeRms": 0.028931119415106666,
|
| 244 |
+
"cosine": 0.9995831520949008,
|
| 245 |
+
"top1Equal": true,
|
| 246 |
+
"finite": true
|
| 247 |
+
},
|
| 248 |
+
"fp16ToGptq": {
|
| 249 |
+
"maxAbs": 5.9765625,
|
| 250 |
+
"relativeRms": 0.3487054531078975,
|
| 251 |
+
"cosine": 0.9377851831391082,
|
| 252 |
+
"top1Equal": true,
|
| 253 |
+
"finite": true
|
| 254 |
+
},
|
| 255 |
+
"gptqToWebgpu": {
|
| 256 |
+
"maxAbs": 0.14453125,
|
| 257 |
+
"relativeRms": 0.01074293845406932,
|
| 258 |
+
"cosine": 0.9999440250098686,
|
| 259 |
+
"top1Equal": true,
|
| 260 |
+
"finite": true
|
| 261 |
+
},
|
| 262 |
+
"passed": true
|
| 263 |
+
},
|
| 264 |
+
{
|
| 265 |
+
"case": "tool_history",
|
| 266 |
+
"step": 2,
|
| 267 |
+
"sourceBf16ToFp16": {
|
| 268 |
+
"maxAbs": 0.3828125,
|
| 269 |
+
"relativeRms": 0.016834366518147053,
|
| 270 |
+
"cosine": 0.9998583938821983,
|
| 271 |
+
"top1Equal": true,
|
| 272 |
+
"finite": true
|
| 273 |
+
},
|
| 274 |
+
"fp16ToGptq": {
|
| 275 |
+
"maxAbs": 5.638671875,
|
| 276 |
+
"relativeRms": 0.3736643910497181,
|
| 277 |
+
"cosine": 0.9318102942626478,
|
| 278 |
+
"top1Equal": true,
|
| 279 |
+
"finite": true
|
| 280 |
+
},
|
| 281 |
+
"gptqToWebgpu": {
|
| 282 |
+
"maxAbs": 0.1328125,
|
| 283 |
+
"relativeRms": 0.007678886224809575,
|
| 284 |
+
"cosine": 0.9999712093288873,
|
| 285 |
+
"top1Equal": true,
|
| 286 |
+
"finite": true
|
| 287 |
+
},
|
| 288 |
+
"passed": true
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"case": "tool_history",
|
| 292 |
+
"step": 3,
|
| 293 |
+
"sourceBf16ToFp16": {
|
| 294 |
+
"maxAbs": 0.328125,
|
| 295 |
+
"relativeRms": 0.030876288162470202,
|
| 296 |
+
"cosine": 0.9995263219302111,
|
| 297 |
+
"top1Equal": true,
|
| 298 |
+
"finite": true
|
| 299 |
+
},
|
| 300 |
+
"fp16ToGptq": {
|
| 301 |
+
"maxAbs": 2.5712890625,
|
| 302 |
+
"relativeRms": 0.2003064180768053,
|
| 303 |
+
"cosine": 0.9805788883889465,
|
| 304 |
+
"top1Equal": true,
|
| 305 |
+
"finite": true
|
| 306 |
+
},
|
| 307 |
+
"gptqToWebgpu": {
|
| 308 |
+
"maxAbs": 0.09375,
|
| 309 |
+
"relativeRms": 0.006090321309410876,
|
| 310 |
+
"cosine": 0.9999814728684856,
|
| 311 |
+
"top1Equal": true,
|
| 312 |
+
"finite": true
|
| 313 |
+
},
|
| 314 |
+
"passed": true
|
| 315 |
+
}
|
| 316 |
+
],
|
| 317 |
+
"packagedProofSha256": "dc91e19a96db79d51d77c15c1e03f755249021ae0fbf3403e4606ed877a664a1",
|
| 318 |
+
"uploadAllowed": false
|
| 319 |
+
}
|
validation/parser-results.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"responseCount": 194,
|
| 3 |
+
"packageParserSha256": "7a33bbcd31cc3910a169e735541c4d5189f85480237577f262de3154ce91f12d",
|
| 4 |
+
"optionalHelperSha256": "0f1bf7265771ec5cf73147c299c52490086579bb2d2c9885cbddda7e067322e3",
|
| 5 |
+
"bundledMatches": 162,
|
| 6 |
+
"bundledMismatchCount": 32,
|
| 7 |
+
"optionalHelperMatches": 194,
|
| 8 |
+
"optionalHelperMismatchCount": 0,
|
| 9 |
+
"optionalHelperAllowlistFailures": 0,
|
| 10 |
+
"smoke": [
|
| 11 |
+
{
|
| 12 |
+
"name": "single_address",
|
| 13 |
+
"sameTypedArguments": true,
|
| 14 |
+
"bundled": {
|
| 15 |
+
"calls": [
|
| 16 |
+
{
|
| 17 |
+
"name": "open_address",
|
| 18 |
+
"args": {
|
| 19 |
+
"address": "https://example.net/guide"
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
"helper": {
|
| 25 |
+
"calls": [
|
| 26 |
+
{
|
| 27 |
+
"name": "open_address",
|
| 28 |
+
"args": {
|
| 29 |
+
"address": "https://example.net/guide"
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
]
|
| 33 |
+
}
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"name": "escaped_address",
|
| 37 |
+
"sameTypedArguments": true,
|
| 38 |
+
"bundled": {
|
| 39 |
+
"calls": [
|
| 40 |
+
{
|
| 41 |
+
"name": "open_address",
|
| 42 |
+
"args": {
|
| 43 |
+
"address": "https://example.net/find?name=blue&sort=recent"
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
]
|
| 47 |
+
},
|
| 48 |
+
"helper": {
|
| 49 |
+
"calls": [
|
| 50 |
+
{
|
| 51 |
+
"name": "open_address",
|
| 52 |
+
"args": {
|
| 53 |
+
"address": "https://example.net/find?name=blue&sort=recent"
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
]
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"name": "typed_labels",
|
| 61 |
+
"sameTypedArguments": false,
|
| 62 |
+
"bundled": {
|
| 63 |
+
"calls": [
|
| 64 |
+
{
|
| 65 |
+
"name": "save_labels",
|
| 66 |
+
"args": {
|
| 67 |
+
"labels": "['green', 'amber']",
|
| 68 |
+
"enabled": "False"
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
]
|
| 72 |
+
},
|
| 73 |
+
"helper": {
|
| 74 |
+
"calls": [
|
| 75 |
+
{
|
| 76 |
+
"name": "save_labels",
|
| 77 |
+
"args": {
|
| 78 |
+
"labels": [
|
| 79 |
+
"green",
|
| 80 |
+
"amber"
|
| 81 |
+
],
|
| 82 |
+
"enabled": false
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
]
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
],
|
| 89 |
+
"originalAuditSha256": "14e167d6a11fb7b87b93dbfcd1d94585a4ab79479bb2e058fa9ec5d5ebfe3030",
|
| 90 |
+
"optionalHelperAutomaticallyIntegrated": false,
|
| 91 |
+
"noToolsExecuted": true
|
| 92 |
+
}
|