@camstack/system 1.2.363 → 1.2.365
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/addon-utils.d.ts +1 -1
- package/dist/addon-utils.js +3 -1
- package/dist/addon-utils.mjs +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-DvV1td5E.js → child-cap-dispatch-C0m_Q3S1.js} +1 -1
- package/dist/{child-cap-dispatch-CKZCOBm0.mjs → child-cap-dispatch-DVawueyL.mjs} +1 -1
- package/dist/{composition-sources-FoswqEZ-.mjs → composition-sources-BMsVkvaT.mjs} +1 -1
- package/dist/{composition-sources-DpynNuXQ.js → composition-sources-BYZglxTf.js} +1 -1
- package/dist/{dist-C-m7Stog.js → dist-B22ObVxi.js} +36 -1
- package/dist/{dist-COE6aOde.mjs → dist-BIGk6VLF.mjs} +19 -2
- package/dist/download/hosted-model-revisions.d.ts +10 -0
- package/dist/download/model-download-service.d.ts +8 -14
- package/dist/download/model-downloader.d.ts +53 -1
- package/dist/{event-loop-stall-monitor-ey4mbofz.js → event-loop-stall-monitor-B687EIFo.js} +376 -114
- package/dist/{event-loop-stall-monitor-EXjzIxDz.mjs → event-loop-stall-monitor-DxiaIssh.mjs} +359 -115
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -3
- package/dist/index.mjs +4 -4
- package/dist/{retired-settings-keys-DzYUNQaI.mjs → retired-settings-keys-C149_dvi.mjs} +1 -1
- package/dist/{retired-settings-keys-BLzKiTzp.js → retired-settings-keys-C8F8g0Oz.js} +1 -1
- package/package.json +1 -1
package/dist/{event-loop-stall-monitor-EXjzIxDz.mjs → event-loop-stall-monitor-DxiaIssh.mjs}
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Lt as hfModelUrl, T as HF_REPO, j as MODEL_FORMATS } from "./dist-BIGk6VLF.mjs";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import * as path$1 from "node:path";
|
|
3
4
|
import path from "node:path";
|
|
@@ -7,6 +8,153 @@ import { promisify } from "node:util";
|
|
|
7
8
|
import { createServer } from "node:http";
|
|
8
9
|
import { brotliCompress, constants as constants$1, gzip } from "node:zlib";
|
|
9
10
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
11
|
+
//#region src/download/hosted-model-revisions.ts
|
|
12
|
+
/**
|
|
13
|
+
* GENERATED by `scripts/check-hosted-model-revisions.ts --write` — DO NOT EDIT.
|
|
14
|
+
*
|
|
15
|
+
* The revision of every artefact on the CamStack model mirror, keyed by its
|
|
16
|
+
* path under `https://huggingface.co/camstack/camstack-models/resolve/main/`: the sha256 (`lfs.oid`)
|
|
17
|
+
* of its weight file (`revisionWeightUrl`). `resolveFormatRevision` reads
|
|
18
|
+
* it for every catalog format hosted there (D743, D744). Regenerate after
|
|
19
|
+
* any upload to the mirror; the script without `--write` says when it is due.
|
|
20
|
+
*/
|
|
21
|
+
var HOSTED_MODEL_REVISIONS = {
|
|
22
|
+
"animalClassification/animal-classifier/coreml/animal-classifier.mlpackage": "2194acb46c1a957c2db766cce0c6f7c295aafc8ad1983843dcb8bc95eac42a34",
|
|
23
|
+
"animalClassification/animal-classifier/onnx/animal-classifier.onnx": "2ccd51865c1d2d600ff68235f5e72a434cb89555197a872489a2357f50771768",
|
|
24
|
+
"animalClassification/animal-classifier/openvino/animal-classifier.xml": "30edf890ff200e8b5169e7a28fcebe148b0d6a5dd3eb570d7a4de89acc9bd63c",
|
|
25
|
+
"animalClassification/bird-classifier/coreml/bird-classifier.mlpackage": "09d5acd27abc89a139399b70ff6711094c05ace5edd6d40b67bf816a41d39a22",
|
|
26
|
+
"animalClassification/bird-classifier/onnx/bird-classifier.onnx": "64dd1b966628145219f2424b42b18b76b8dc33a0a9d9ce90b8c057397fa76da2",
|
|
27
|
+
"animalClassification/bird-classifier/openvino/bird-classifier.xml": "bef863425e1774fba8bf8809a4d690466eeaf183e8d9278493a584a436304339",
|
|
28
|
+
"animalClassification/bird-classifier/tflite/bird-classifier_edgetpu.tflite": "f5b37245cfda13909a34264df58784981aef8dde3bc8604e0ee42caeba29229c",
|
|
29
|
+
"audioClassification/yamnet/onnx/camstack-yamnet.onnx": "d7459a0aefffef8c1ccc60c8e0a0f0758a724fc1b55b47194b418029e938ea26",
|
|
30
|
+
"audioClassification/yamnet/openvino/camstack-yamnet.xml": "11d9e8f47f8af09245bf6a519bc9967b1ead9ac8f8e89d985289ac0fb07926b7",
|
|
31
|
+
"clip/siglip2/coreml/camstack-siglip2-b16-224-vision.mlpackage": "6fdf1936f91d40a4b9b4fcaabe5b2dcadfc6d8c0e76ab1cc9e18c38e95d60787",
|
|
32
|
+
"clip/siglip2/onnx/camstack-siglip2-b16-224-text.onnx": "df6ffc0c44a49648f903fbf6c46722de416447d065e63db97bd3f8edd9bfc411",
|
|
33
|
+
"clip/siglip2/openvino/camstack-siglip2-b16-224-text.xml": "a85203c195eccea00c9d31af5f3594733353cc6b3a3c2802b4e32dc0136f8dae",
|
|
34
|
+
"clip/siglip2/openvino/camstack-siglip2-b16-224-vision.xml": "2e190c41cfa980c8a7a24cb13ecdd71ae0a08eb8665c22a27314aec64e78f325",
|
|
35
|
+
"faceDetection/yunet/coreml/camstack-yunet-2023mar.mlpackage": "d6296bc3ae3048bf3815ef7df8ee934fde48018276c0b2278f93ba359556103b",
|
|
36
|
+
"faceDetection/yunet/onnx/camstack-yunet-2023mar.onnx": "55df63fd5a5128903ee2b6dd4315aa82979be9a1d6cf83cc154b74cd4bd2c42f",
|
|
37
|
+
"faceDetection/yunet/openvino/camstack-yunet-2023mar.xml": "c246c87702b346a9d1de7a70ea61b256d06c7db59bd895acb1aadeaba1985dff",
|
|
38
|
+
"faceDetection/yunet/tflite/camstack-yunet-2023mar_edgetpu.tflite": "b7214dafaf18b8a5c55c7ea502c783e6a356043c2900ff9e02515a368285e982",
|
|
39
|
+
"faceRecognition/auraface/coreml/camstack-auraface-r100.mlpackage": "c189aaf7d6758dafb1603b4ea7f7c2161b69639434ddbce800e0cc632b26d7e0",
|
|
40
|
+
"faceRecognition/auraface/onnx/camstack-auraface-r100.onnx": "1c050a0fd76a5770fb94bd35d1ff99648cb31385280d7fba43284b9b6e63277f",
|
|
41
|
+
"faceRecognition/auraface/openvino/camstack-auraface-r100.xml": "e8f53b3a4bc7d13520d561d2610887bffe8438fac71a496ec1cfcce2616734bb",
|
|
42
|
+
"objectDetection/yolo26/coreml/camstack-yolo26l-256.mlpackage": "87968708ab7ee99aac97d1d6644f6b70149b7b2c38b3f2c3c64326c3cc2333e2",
|
|
43
|
+
"objectDetection/yolo26/coreml/camstack-yolo26l-320.mlpackage": "f0a136258aa69978f5647e07ac4019a4f8c8745dc6d6500c8e3a2876d041f9e5",
|
|
44
|
+
"objectDetection/yolo26/coreml/camstack-yolo26l.mlpackage": "b53d9ce65fc0f84dd13e460bf2666362ac6854f645c897dd0e0c6e8691995146",
|
|
45
|
+
"objectDetection/yolo26/coreml/camstack-yolo26m-256.mlpackage": "bf1ac4cb5f2a3749815a36dde6d6e57ce0662a005ccefd435283d4e38c21298d",
|
|
46
|
+
"objectDetection/yolo26/coreml/camstack-yolo26m-320.mlpackage": "4cf582bf1b14fb7abf87f61a1cf198ad2626fedec32873224bc6f2411e6680b7",
|
|
47
|
+
"objectDetection/yolo26/coreml/camstack-yolo26m.mlpackage": "e9a3751fd3c60676ce94fba7d3d9e8cccfcc8711cd55025eb8837ad8b0fe1424",
|
|
48
|
+
"objectDetection/yolo26/coreml/camstack-yolo26n-256.mlpackage": "1c0565e40b4e04194561df09de4c007ccedd4d5d784adf2341f3af7c97f42cb9",
|
|
49
|
+
"objectDetection/yolo26/coreml/camstack-yolo26n-320.mlpackage": "b30bb5ced9c127f0a813c7740c451a1766226dde43e277e01eb9d298d44f17cd",
|
|
50
|
+
"objectDetection/yolo26/coreml/camstack-yolo26n.mlpackage": "1e176157d427b358db9d87613b1a57040d20c7d0b4a7de70e4477e162dd3d4c5",
|
|
51
|
+
"objectDetection/yolo26/coreml/camstack-yolo26s-256.mlpackage": "e4f3ba3ba99d9a068c4e064fd74427b8a2b56c5e1f56f56979886a493068fbd0",
|
|
52
|
+
"objectDetection/yolo26/coreml/camstack-yolo26s-320.mlpackage": "156d8db8d1f2b9d6bc23ce2e123889d6ad79a5ce866dfccc35c0d869df79db64",
|
|
53
|
+
"objectDetection/yolo26/coreml/camstack-yolo26s.mlpackage": "6d760c59e32daea2812258bd6db417ddfc2eb1be6184daef54ba349bd8d0d125",
|
|
54
|
+
"objectDetection/yolo26/coreml/camstack-yolo26x.mlpackage": "62871ed80cd80cf2b742d2a1ac3ff83f534d9f51039febcb966ee173851fcd5d",
|
|
55
|
+
"objectDetection/yolo26/onnx/camstack-yolo26l-256.onnx": "1a5a963e9b76a324e2fa0e111d96b23176e47a5337e12576a755b512f843592b",
|
|
56
|
+
"objectDetection/yolo26/onnx/camstack-yolo26l-320.onnx": "15ee305cb925934dd73d15a398cc76adf8a51ffa430b11da1ba61f3686eb24b3",
|
|
57
|
+
"objectDetection/yolo26/onnx/camstack-yolo26l.onnx": "62e55ec70eb11f19e75c519a10c1632e08d38a9ddb3229450156a6b423780bbc",
|
|
58
|
+
"objectDetection/yolo26/onnx/camstack-yolo26m-256.onnx": "3d2df9b07b06bfafc6487200674ecb899957e56acbf2ea64383ad477cab30072",
|
|
59
|
+
"objectDetection/yolo26/onnx/camstack-yolo26m-320.onnx": "6a4fc7a9a0c61cf2a401407805bb850b49dbe1faf1cf0ae2edc794a8bc61cc51",
|
|
60
|
+
"objectDetection/yolo26/onnx/camstack-yolo26m.onnx": "907982ada658a53736edfcbdde7e9cf0489a54c058da0deea106bcb2794fe6bc",
|
|
61
|
+
"objectDetection/yolo26/onnx/camstack-yolo26n-256.onnx": "352b15664cea1af55f80f96e9b7a0f8338ca2e6b6053bc27152ad82fc689cb58",
|
|
62
|
+
"objectDetection/yolo26/onnx/camstack-yolo26n-320.onnx": "22d8f1c749394509161b9053361dec19be23c3479f0386a50caba418e7e897a7",
|
|
63
|
+
"objectDetection/yolo26/onnx/camstack-yolo26n.onnx": "8f2e6c82ccbc63153c2284546880b1310d832d2b75efea67cb9cda1fa35da968",
|
|
64
|
+
"objectDetection/yolo26/onnx/camstack-yolo26s-256.onnx": "354ff62da4ffd763f1e7b8761c5d070c1d3f3eafc5221a1a52a3f5b8e651471b",
|
|
65
|
+
"objectDetection/yolo26/onnx/camstack-yolo26s-320.onnx": "465069e0eb3d44e45c2de2c57a57c9ff6f1466cda0816d7ca05ce15e388b0ae3",
|
|
66
|
+
"objectDetection/yolo26/onnx/camstack-yolo26s.onnx": "d2e7ed3e5ef3b7fac18628c63d2bef0d5ae144cb2c239b195eb90ff96437fed5",
|
|
67
|
+
"objectDetection/yolo26/onnx/camstack-yolo26x.onnx": "6d10ddc274ea5e6597c69471a3e122eee7a4cb2a831c9449b30b0e69f4349133",
|
|
68
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-256-int8.xml": "d59a9920857a48d27bda14b1cbe3ef1390e1032c37a822cbc567f2a03d1f5e2f",
|
|
69
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-256.xml": "0c78828d4abe9858bb7ff543ee656adb874c11a76cbacbdcca7777d356be2ee3",
|
|
70
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-320-int8.xml": "9c441c07c7c2d47982b44a2f2d22af0d77ffd466f7279b843c9bbe21cd07a5d8",
|
|
71
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-320.xml": "0c78828d4abe9858bb7ff543ee656adb874c11a76cbacbdcca7777d356be2ee3",
|
|
72
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-fp16.xml": "653a3bf71753672f56a2c8dae65195c8c99029abb3d3d7a42e25860a2071df39",
|
|
73
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l-int8.xml": "9e2c1de16b3533c0f8d2ed58e385515bbcb6ab40231bdace5b922795b88127be",
|
|
74
|
+
"objectDetection/yolo26/openvino/camstack-yolo26l.xml": "653a3bf71753672f56a2c8dae65195c8c99029abb3d3d7a42e25860a2071df39",
|
|
75
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-256-int8.xml": "01c747e08fbac6fedfc874924a267ba3d5597823b8d91c1c39f5db765047cfd8",
|
|
76
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-256.xml": "c5a4c729eceaec91f6af5077fa34b6f5cc17bc2130d07dc13ed883966e15902e",
|
|
77
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-320-int8.xml": "2b6be63ad9012c85976223ed46c63b80208479544f13221575f62c4b5a815314",
|
|
78
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-320.xml": "c5a4c729eceaec91f6af5077fa34b6f5cc17bc2130d07dc13ed883966e15902e",
|
|
79
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-fp16.xml": "4990e60c17e6e1158dca28750e7a50c3a6c72cac4fd1bbac73bba52ac3647c39",
|
|
80
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m-int8.xml": "7cf3df0dd16d58468ad6ac185ec5f38ac6e20a49069f049007b6c0607586a6f7",
|
|
81
|
+
"objectDetection/yolo26/openvino/camstack-yolo26m.xml": "4990e60c17e6e1158dca28750e7a50c3a6c72cac4fd1bbac73bba52ac3647c39",
|
|
82
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-256-int8.xml": "acf0ed987bbd43bd819c9f061582c0ba17aa4a3f6bf55f0c8c7049486742f745",
|
|
83
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-256.xml": "caf498d56ba2288a54734b4d2c73737f77261d1410357f25998e00655c661736",
|
|
84
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-320-int8.xml": "639e4d54a0d5c6a17d02859a9b46c0ff4d404fbe0582e48ed3df4b8364867316",
|
|
85
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-320.xml": "caf498d56ba2288a54734b4d2c73737f77261d1410357f25998e00655c661736",
|
|
86
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-fp16.xml": "77f9da9a6330b130d21e7d9d2338b8f82f3541491c24566b80b4ff2852559b2d",
|
|
87
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n-int8.xml": "92068cd26433694188cf383e3a7c3cc49a36de58387a8012de9c3768080781f3",
|
|
88
|
+
"objectDetection/yolo26/openvino/camstack-yolo26n.xml": "77f9da9a6330b130d21e7d9d2338b8f82f3541491c24566b80b4ff2852559b2d",
|
|
89
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-256-int8.xml": "483ca9622c3bb398c414cb3ae412bcab26aeb807c91f4d84dcd42356ce54c885",
|
|
90
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-256.xml": "8e4c513ffe7d571ed1e9545a990a43f6683a8bde04bdc580fdfd8c62e4e3193f",
|
|
91
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-320-int8.xml": "c02030199cda5083e41599c7aa9dd64d03597e033f03b61c62194de49719de65",
|
|
92
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-320.xml": "8e4c513ffe7d571ed1e9545a990a43f6683a8bde04bdc580fdfd8c62e4e3193f",
|
|
93
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-fp16.xml": "bb9355b5e559d646256ad80e4fc2f965c1c1f4905da3c014b7f15bb3d48d9d34",
|
|
94
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s-int8.xml": "863bbfa6f45b617d5600ceb5488a2dc3c0d573b658e761a5c269b86f3f6cca77",
|
|
95
|
+
"objectDetection/yolo26/openvino/camstack-yolo26s.xml": "bb9355b5e559d646256ad80e4fc2f965c1c1f4905da3c014b7f15bb3d48d9d34",
|
|
96
|
+
"objectDetection/yolo26/openvino/camstack-yolo26x-fp16.xml": "053f64a4dc9c3b81d0b6c1a567c0d0b403eeb33a6771170712c4de1c09fc6f15",
|
|
97
|
+
"objectDetection/yolo26/openvino/camstack-yolo26x-int8.xml": "c1f374e058de562d3a848b93d6b39dd9ccb772e2f34f4c0dec4e0bb7787cfd2f",
|
|
98
|
+
"objectDetection/yolo26/openvino/camstack-yolo26x.xml": "053f64a4dc9c3b81d0b6c1a567c0d0b403eeb33a6771170712c4de1c09fc6f15",
|
|
99
|
+
"objectDetection/yolov9/coreml/camstack-yolov9c-320.mlpackage": "7999f25b805f92c732a450625021cda97b7185f8c9f98be28be82be1529fe171",
|
|
100
|
+
"objectDetection/yolov9/coreml/camstack-yolov9c-640.mlpackage": "9889ababc524db385a4305ebc1a42ada4dddc8028198d040fbba77c504228932",
|
|
101
|
+
"objectDetection/yolov9/coreml/camstack-yolov9m-320.mlpackage": "e0e0298051c71c79390f1a05f71a2bb882af52c096c70d69674afb84077f6de4",
|
|
102
|
+
"objectDetection/yolov9/coreml/camstack-yolov9m-640.mlpackage": "4c56eef689435b427c53e92e918be386781024c9b77492f9e486dcdd8ea3570c",
|
|
103
|
+
"objectDetection/yolov9/coreml/camstack-yolov9s-320.mlpackage": "6408badb44161268a337f87586ad82f40e4e315a58be460a648407cc38097675",
|
|
104
|
+
"objectDetection/yolov9/coreml/camstack-yolov9s-640.mlpackage": "9f68b8d418b0832e9788f115e2dfabc6ff54fbe5244815adafa0bd9f98204755",
|
|
105
|
+
"objectDetection/yolov9/coreml/camstack-yolov9t-320.mlpackage": "531aa2d14e7e321f2c90219b966cc3781781d0304c7bed7e6c3b75adaa2ada86",
|
|
106
|
+
"objectDetection/yolov9/coreml/camstack-yolov9t-640.mlpackage": "53dfec9857b3c9922fcbd5e9f88f34ed79de26d9bbcf0d705a1c7a4e5ac93398",
|
|
107
|
+
"objectDetection/yolov9/onnx/camstack-yolov9c-320.onnx": "41b48ef6b39f76340c9a2d40182eddf46ab311b68efbdf637148358f27f1f351",
|
|
108
|
+
"objectDetection/yolov9/onnx/camstack-yolov9c-640.onnx": "4b89e489c4f724ae6c7f271350c9bfd4c800c535e1699f2d6b2d7714293bb695",
|
|
109
|
+
"objectDetection/yolov9/onnx/camstack-yolov9m-320.onnx": "602acf6a2189ad713e5aa0393a3b47c04c8303d6907762f66424f168c3e1e55b",
|
|
110
|
+
"objectDetection/yolov9/onnx/camstack-yolov9m-640.onnx": "d0e69881f62ad156ccbe8699611ae2bd4e569431a9c020b3b6a681efdcd1cfea",
|
|
111
|
+
"objectDetection/yolov9/onnx/camstack-yolov9s-320.onnx": "e06ee6345026ab95f90f5f367b01164654376725fa8e263067ebb9f3417f89c3",
|
|
112
|
+
"objectDetection/yolov9/onnx/camstack-yolov9s-640.onnx": "9113734de682b6b9147b8ed331684d4dc65ddc58d33dd95a00d507c88e82b5c4",
|
|
113
|
+
"objectDetection/yolov9/onnx/camstack-yolov9t-320.onnx": "6c0b0a302a5aaabaf17749a3bda15588a0b196d6f16363198b678c68d2aa5d17",
|
|
114
|
+
"objectDetection/yolov9/onnx/camstack-yolov9t-640.onnx": "fd025ab7bf4d81d506a0561917813431dabe3d673aea4182ff61d7e5c803c2c8",
|
|
115
|
+
"objectDetection/yolov9/openvino/camstack-yolov9c-320-fp16.xml": "3bacbbd621df5570d25dc28b4371cd46847f252743a5246481efffbbc63b5c31",
|
|
116
|
+
"objectDetection/yolov9/openvino/camstack-yolov9c-320-int8.xml": "7614b514c12e03a35a697ed884abd26db1ed8b4ebb5288f8b9e7daf8335909ea",
|
|
117
|
+
"objectDetection/yolov9/openvino/camstack-yolov9c-640-fp16.xml": "702060a1904f8de7eb68b72ad5024976767ba546c3dc941f8b7c2e5d1a236d0d",
|
|
118
|
+
"objectDetection/yolov9/openvino/camstack-yolov9c-640-int8.xml": "3bda3338e0280108a32b6ae638637cd9a2b2a563b8c8ec328165372ee9d55bd9",
|
|
119
|
+
"objectDetection/yolov9/openvino/camstack-yolov9m-320-fp16.xml": "d381e5981e08bad4b8333bba3db48b4c0885883eb1bd524c71e69e2d8b745eaf",
|
|
120
|
+
"objectDetection/yolov9/openvino/camstack-yolov9m-320-int8.xml": "59e5274ed17b2acb57c9ba6999e2e92ea6f05e153fc11e6f8f19bd4973d36a74",
|
|
121
|
+
"objectDetection/yolov9/openvino/camstack-yolov9m-640-fp16.xml": "a64e8867a406c448e65fecea16932d759d85249427c6b43770387904d980d6aa",
|
|
122
|
+
"objectDetection/yolov9/openvino/camstack-yolov9m-640-int8.xml": "b229989cc83ad3c82a3c7f09a25c522eb25416a9d5ce9f1b58225ef4668694b5",
|
|
123
|
+
"objectDetection/yolov9/openvino/camstack-yolov9s-320-fp16.xml": "d07a908f4e44d3b482fad99fd280e1eff7f12546848b3acdfd478407a12fbaf6",
|
|
124
|
+
"objectDetection/yolov9/openvino/camstack-yolov9s-320-int8.xml": "c8c58877a7a3b969ecfced15244c027eb9b9295a82cae54b71197a1a0dbb31f8",
|
|
125
|
+
"objectDetection/yolov9/openvino/camstack-yolov9s-640-fp16.xml": "19448578cde92005a143b8de9655e767032e608cea496e154273ed05a97bed1f",
|
|
126
|
+
"objectDetection/yolov9/openvino/camstack-yolov9s-640-int8.xml": "7ea8b3d6bc98f15b2eada4e62cdcc35c211a181cbddf51251a11e97bee994fdd",
|
|
127
|
+
"objectDetection/yolov9/openvino/camstack-yolov9t-320-fp16.xml": "2f4dc7d06d49af8008fb3da0cdc04a35fdfbc5fafbb2f069822edd826fcc49de",
|
|
128
|
+
"objectDetection/yolov9/openvino/camstack-yolov9t-320-int8.xml": "4b3964c53d2617502aea7bc07fd5fe24da82b27896abe12fd87956b2765babf6",
|
|
129
|
+
"objectDetection/yolov9/openvino/camstack-yolov9t-640-fp16.xml": "d4dd2278941ccb210d0763d822353f6d951c6a4f4f5a1604d7e3536ce6ffb954",
|
|
130
|
+
"objectDetection/yolov9/openvino/camstack-yolov9t-640-int8.xml": "75e45bcf26fe37489d66ae306c3b7c08742b3f2af3c84cd5e41d0520aaef91bf",
|
|
131
|
+
"packageDetection/rfdetr-package/coreml/camstack-rfdetr-package.mlpackage": "73e42f03d66011a311bd83a0a3d1890e7eb1b9b2ba2b5688552a5d4fd60e0e72",
|
|
132
|
+
"packageDetection/rfdetr-package/onnx/camstack-rfdetr-package.onnx": "5af96c6b5936f179e317c9e3915b7c7f74ea3625355f97f6a071c3cd5af2475c",
|
|
133
|
+
"packageDetection/rfdetr-package/openvino/camstack-rfdetr-package.xml": "e2cb5bbccb7809d5c7e691a957bc5e008084119bdf29e2c95d6b6b0791e3061a",
|
|
134
|
+
"plateDetection/yolox-tiny-plate/coreml/camstack-yolox-tiny-plate.mlpackage": "a26ae8fe32e458f7396d56bed83b1243e6067f435b08cd6da134273b9151447d",
|
|
135
|
+
"plateDetection/yolox-tiny-plate/onnx/camstack-yolox-tiny-plate.onnx": "f57b5618eafe91bab19bbdcd9af9b0671dbdba30d76a6e0a3a86b0db24bb1ae6",
|
|
136
|
+
"plateDetection/yolox-tiny-plate/openvino/camstack-yolox-tiny-plate.xml": "83b808eb8fcda6f852477e2dbcdd5cad29ab6a8a58e90017714f167c6a345c27",
|
|
137
|
+
"plateDetection/yolox-tiny-plate/tflite/camstack-yolox-tiny-plate_edgetpu.tflite": "0e091263e9c93063f9da822387860a9cd21c0a554e714de276140921487b8e4d",
|
|
138
|
+
"plateRecognition/cct-s-v2-global/coreml/camstack-cct-s-v2-global.mlpackage": "31b9aba671d98ebd847f43a9e2555f7664c70ad11c3e42fdc0add528463fd3ee",
|
|
139
|
+
"plateRecognition/cct-s-v2-global/onnx/camstack-cct-s-v2-global.onnx": "79c3c00f906857e63453bc16cef6b4a0d34821dff685328eff565fd2da559d21",
|
|
140
|
+
"plateRecognition/cct-s-v2-global/openvino/camstack-cct-s-v2-global.xml": "7357db8b5f1c71a8af9376f2e35435bd0c0361f5193b7e02787f513514ecb8ab",
|
|
141
|
+
"segmentation/yolo26-seg/coreml/camstack-yolo26m-seg.mlpackage": "77ac5c932948df6c6d30f232b40302ccbdfc00f97f7fa78a90dbfb7cdb97608f",
|
|
142
|
+
"segmentation/yolo26-seg/coreml/camstack-yolo26n-seg.mlpackage": "81863a6503294d06063a3320de0a45d543d62b9a3d11009c8d54f5d626abd2a0",
|
|
143
|
+
"segmentation/yolo26-seg/coreml/camstack-yolo26s-seg.mlpackage": "47ee5d620a141bffd594afaf84c4362de2ccf74e036b71ec55ae53428ffbdde8",
|
|
144
|
+
"segmentation/yolo26-seg/onnx/camstack-yolo26m-seg.onnx": "c419fdc8cb8e65c8707586f461d59910487392a5b01711cac674559275df1f7b",
|
|
145
|
+
"segmentation/yolo26-seg/onnx/camstack-yolo26n-seg.onnx": "9f2480a359c8a44541b931d44c4a47898122a5b16ce78d8e5611351b1d4531b8",
|
|
146
|
+
"segmentation/yolo26-seg/onnx/camstack-yolo26s-seg.onnx": "88454cc2f5c2ebaf197536568ffb2ae146a48a85c5c053fd8c9f72f117262313",
|
|
147
|
+
"segmentation/yolo26-seg/openvino/camstack-yolo26m-seg.xml": "08eea0ff1ff6b66a03eb255b9a9ce6952908c92c4684347672d666731148b28f",
|
|
148
|
+
"segmentation/yolo26-seg/openvino/camstack-yolo26n-seg.xml": "d592be6c57fb6f0fc00277327b2421d7ec91fbc0da050bd97fab227df1158c5e",
|
|
149
|
+
"segmentation/yolo26-seg/openvino/camstack-yolo26s-seg.xml": "c4508b20dbfe644220850cfc294e99c9fc396bd61443fcc8db8801a4388e9d99",
|
|
150
|
+
"segmentationRefiner/u2netp/coreml/camstack-u2netp.mlpackage": "67a1172b99e8b34493482b0095bcfe9960d423315a9bfe619b149ea7ba187e05",
|
|
151
|
+
"segmentationRefiner/u2netp/onnx/camstack-u2netp.onnx": "309c8469258dda742793dce0ebea8e6dd393174f89934733ecc8b14c76f4ddd8",
|
|
152
|
+
"segmentationRefiner/u2netp/openvino/camstack-u2netp.xml": "d060dec1fd64855daef223f635cb280f174415785318d4dc78af0d86de025397",
|
|
153
|
+
"vehicleClassification/vehicle-type-v1/coreml/vehicle-type-v1.mlpackage": "26cf66168010daa0a1d33a2fc12305e0e7465c977840861b4bf470c8cae8a7b8",
|
|
154
|
+
"vehicleClassification/vehicle-type-v1/onnx/vehicle-type-v1.onnx": "5153b77de54286bcfefddfdfec9e3c1101b10c30bc33e9181cf8c04e0156818f",
|
|
155
|
+
"vehicleClassification/vehicle-type-v1/openvino/vehicle-type-v1.xml": "bf352f4a602d5e6ef5b6df5140972ef68e79076be397a90c10f1efdda59f4a1e"
|
|
156
|
+
};
|
|
157
|
+
//#endregion
|
|
10
158
|
//#region src/download/model-downloader.ts
|
|
11
159
|
function isNonEmptyFile(filePath) {
|
|
12
160
|
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
@@ -211,22 +359,23 @@ async function computeSha256(filePath) {
|
|
|
211
359
|
});
|
|
212
360
|
}
|
|
213
361
|
/**
|
|
214
|
-
* Download every file in a HuggingFace directory bundle (e.g
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* exposed as a standalone for catalog-less callers.
|
|
362
|
+
* Download every file in a HuggingFace directory bundle (e.g. `.mlpackage`)
|
|
363
|
+
* atomically. `knownFiles` lists the relative paths inside the directory; a
|
|
364
|
+
* bundle that declares none is listed through the Hugging Face tree API. The
|
|
365
|
+
* staging directory replaces `destDir` only when every file arrived, so a
|
|
366
|
+
* bundle already on disk keeps serving until then.
|
|
220
367
|
*/
|
|
221
368
|
async function downloadDirectory(url, destDir, knownFiles, onProgress) {
|
|
222
369
|
const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
|
|
223
370
|
if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
|
|
224
371
|
const [, repo, dirPath] = match;
|
|
225
|
-
|
|
372
|
+
if (repo === void 0 || dirPath === void 0) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
|
|
373
|
+
const relativePaths = knownFiles !== void 0 && knownFiles.length > 0 ? knownFiles : (await listHfFiles(repo, dirPath)).map((f) => f.substring(dirPath.length + 1));
|
|
374
|
+
if (relativePaths.length === 0) throw new Error(`No files found in HuggingFace directory: ${dirPath}`);
|
|
375
|
+
const files = relativePaths.map((f) => ({
|
|
226
376
|
relativePath: f,
|
|
227
377
|
fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
|
|
228
378
|
}));
|
|
229
|
-
if (files.length === 0) throw new Error(`Directory bundle requires explicit \`files\` list (got none for ${url})`);
|
|
230
379
|
const tmpDir = destDir + ".downloading";
|
|
231
380
|
fs.rmSync(tmpDir, {
|
|
232
381
|
recursive: true,
|
|
@@ -256,6 +405,149 @@ async function downloadDirectory(url, destDir, knownFiles, onProgress) {
|
|
|
256
405
|
throw err;
|
|
257
406
|
}
|
|
258
407
|
}
|
|
408
|
+
function isHfTreeEntry(value) {
|
|
409
|
+
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && "path" in value && typeof value.path === "string";
|
|
410
|
+
}
|
|
411
|
+
/** Every file path (repo-relative) under `dirPath`, recursively, via the HF tree API. */
|
|
412
|
+
async function listHfFiles(repo, dirPath) {
|
|
413
|
+
const listing = await fetchJson(`https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`);
|
|
414
|
+
if (!Array.isArray(listing)) throw new Error(`Unexpected HuggingFace tree for ${dirPath}`);
|
|
415
|
+
const files = [];
|
|
416
|
+
for (const entry of listing) {
|
|
417
|
+
if (!isHfTreeEntry(entry)) continue;
|
|
418
|
+
if (entry.type === "file") files.push(entry.path);
|
|
419
|
+
else if (entry.type === "directory") files.push(...await listHfFiles(repo, entry.path));
|
|
420
|
+
}
|
|
421
|
+
return files;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Where a node records the catalog `revision` of the format it downloaded:
|
|
425
|
+
* a sibling of the file or bundle, `<name>.revision` (D743). Outside the
|
|
426
|
+
* bundle, so a `.mlpackage` keeps exactly the hosted files.
|
|
427
|
+
*/
|
|
428
|
+
function revisionRecordPath(modelPath) {
|
|
429
|
+
return `${modelPath}.revision`;
|
|
430
|
+
}
|
|
431
|
+
function readRevisionRecord(modelPath) {
|
|
432
|
+
try {
|
|
433
|
+
return fs.readFileSync(revisionRecordPath(modelPath), "utf8").trim();
|
|
434
|
+
} catch {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/** The CamStack model mirror. Every artefact under it has a generated revision. */
|
|
439
|
+
var HOSTED_MODEL_MIRROR_PREFIX = hfModelUrl(HF_REPO, "");
|
|
440
|
+
/**
|
|
441
|
+
* The revision a format must be at — the ONE rule every model download path
|
|
442
|
+
* reads (D743, D744). An inline `revision` wins; otherwise a format hosted on
|
|
443
|
+
* the CamStack mirror takes the revision generated for its path from the
|
|
444
|
+
* mirror's LFS metadata (`hosted-model-revisions.ts`); anything else has none.
|
|
445
|
+
*/
|
|
446
|
+
function resolveFormatRevision(formatEntry) {
|
|
447
|
+
if (formatEntry.revision !== void 0) return formatEntry.revision;
|
|
448
|
+
if (!formatEntry.url.startsWith(HOSTED_MODEL_MIRROR_PREFIX)) return void 0;
|
|
449
|
+
return HOSTED_MODEL_REVISIONS[formatEntry.url.slice(HOSTED_MODEL_MIRROR_PREFIX.length)];
|
|
450
|
+
}
|
|
451
|
+
/** The member of a Core ML package that holds its weights. */
|
|
452
|
+
var COREML_WEIGHT_MEMBER = "Data/com.apple.CoreML/weights/weight.bin";
|
|
453
|
+
function revisionWeightFile(formatEntry) {
|
|
454
|
+
if (formatEntry.isDirectory) return formatEntry.url.endsWith(".mlpackage") ? {
|
|
455
|
+
in: "bundle",
|
|
456
|
+
member: COREML_WEIGHT_MEMBER
|
|
457
|
+
} : null;
|
|
458
|
+
const weights = siblingFilesFor(formatEntry).find((f) => f.endsWith(".bin"));
|
|
459
|
+
return weights !== void 0 ? {
|
|
460
|
+
in: "sibling",
|
|
461
|
+
name: weights
|
|
462
|
+
} : { in: "main" };
|
|
463
|
+
}
|
|
464
|
+
/** Where the revision's weight file is hosted — what the mirror's `lfs.oid` describes. */
|
|
465
|
+
function revisionWeightUrl(formatEntry) {
|
|
466
|
+
const weights = revisionWeightFile(formatEntry);
|
|
467
|
+
if (weights === null) return null;
|
|
468
|
+
switch (weights.in) {
|
|
469
|
+
case "bundle": return `${formatEntry.url}/${weights.member}`;
|
|
470
|
+
case "sibling": return siblingUrl(formatEntry.url, weights.name);
|
|
471
|
+
case "main": return formatEntry.url;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function revisionWeightPath(modelsDir, modelPath, formatEntry) {
|
|
475
|
+
const weights = revisionWeightFile(formatEntry);
|
|
476
|
+
if (weights === null) return null;
|
|
477
|
+
switch (weights.in) {
|
|
478
|
+
case "bundle": return path$1.join(modelPath, weights.member);
|
|
479
|
+
case "sibling": return path$1.join(modelsDir, weights.name);
|
|
480
|
+
case "main": return modelPath;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* True when the copy at `modelPath` is RECORDED at the revision the format
|
|
485
|
+
* must be at. A format without a revision is current whenever it is present
|
|
486
|
+
* (the behaviour before revisions existed); with one, the node's record must
|
|
487
|
+
* match it — no record means the copy has not been proven current yet.
|
|
488
|
+
*/
|
|
489
|
+
function isCurrentRevision(modelPath, formatEntry) {
|
|
490
|
+
const revision = resolveFormatRevision(formatEntry);
|
|
491
|
+
return revision === void 0 || readRevisionRecord(modelPath) === revision;
|
|
492
|
+
}
|
|
493
|
+
function writeRevisionRecord(modelPath, revision) {
|
|
494
|
+
if (revision === void 0) return;
|
|
495
|
+
const record = revisionRecordPath(modelPath);
|
|
496
|
+
const tmp = `${record}.tmp`;
|
|
497
|
+
fs.writeFileSync(tmp, `${revision}\n`);
|
|
498
|
+
fs.renameSync(tmp, record);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Prove an unrecorded (or differently recorded) copy current by hashing its
|
|
502
|
+
* weight file: when it IS the revision, record it and skip the download. This
|
|
503
|
+
* is what keeps a new revision from re-downloading every copy that already
|
|
504
|
+
* holds the right bytes — a copy fetched before revisions existed, one that a
|
|
505
|
+
* hub distributed, one fetched before the catalog caught up with the mirror.
|
|
506
|
+
*/
|
|
507
|
+
async function adoptByHash(modelsDir, modelPath, formatEntry) {
|
|
508
|
+
const revision = resolveFormatRevision(formatEntry);
|
|
509
|
+
if (revision === void 0) return false;
|
|
510
|
+
const weights = revisionWeightPath(modelsDir, modelPath, formatEntry);
|
|
511
|
+
if (weights === null || !isNonEmptyFile(weights)) return false;
|
|
512
|
+
if (await computeSha256(weights) !== revision) return false;
|
|
513
|
+
writeRevisionRecord(modelPath, revision);
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
/** True when every file of the format is on disk, whatever revision it holds. */
|
|
517
|
+
function isCompleteCopy(modelsDir, modelPath, formatEntry) {
|
|
518
|
+
if (!fs.existsSync(modelPath)) return false;
|
|
519
|
+
if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
|
|
520
|
+
if (fs.statSync(modelPath).size <= 0) return false;
|
|
521
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(modelsDir, f)));
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Replace a single-file format and its siblings that are already on disk.
|
|
525
|
+
* `downloadFile` keeps an existing file, so every file is fetched to a
|
|
526
|
+
* `.updating` name first and moved over the old one only when ALL of them
|
|
527
|
+
* arrived: a failed fetch leaves the old copy serving.
|
|
528
|
+
*/
|
|
529
|
+
async function replaceSingleFileFormat(url, modelPath, modelsDir, siblings, onProgress) {
|
|
530
|
+
const parts = [{
|
|
531
|
+
url,
|
|
532
|
+
dest: modelPath
|
|
533
|
+
}, ...siblings.map((f) => ({
|
|
534
|
+
url: siblingUrl(url, f),
|
|
535
|
+
dest: path$1.join(modelsDir, f)
|
|
536
|
+
}))].map((p) => ({
|
|
537
|
+
...p,
|
|
538
|
+
staged: `${p.dest}.updating`
|
|
539
|
+
}));
|
|
540
|
+
try {
|
|
541
|
+
for (const [i, part] of parts.entries()) {
|
|
542
|
+
fs.rmSync(part.staged, { force: true });
|
|
543
|
+
await downloadFile(part.url, part.staged, i === 0 ? (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total) : void 0);
|
|
544
|
+
}
|
|
545
|
+
} catch (err) {
|
|
546
|
+
for (const part of parts) fs.rmSync(part.staged, { force: true });
|
|
547
|
+
throw err;
|
|
548
|
+
}
|
|
549
|
+
for (const part of parts) fs.renameSync(part.staged, part.dest);
|
|
550
|
+
}
|
|
259
551
|
/**
|
|
260
552
|
* Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
|
|
261
553
|
* (or directory bundle) + extra files (labels JSON, charset dict, …),
|
|
@@ -268,19 +560,54 @@ async function ensureModel(modelsDir, entry, format, onProgress) {
|
|
|
268
560
|
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
269
561
|
const modelPath = path$1.join(modelsDir, filename);
|
|
270
562
|
const siblings = siblingFilesFor(formatEntry);
|
|
563
|
+
let outdated = false;
|
|
271
564
|
if (fs.existsSync(modelPath)) if (formatEntry.isDirectory && !fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
|
|
272
565
|
recursive: true,
|
|
273
566
|
force: true
|
|
274
567
|
});
|
|
275
|
-
else if (siblings.some((f) => !isNonEmptyFile(path$1.join(modelsDir, f))))
|
|
568
|
+
else if (siblings.some((f) => !isNonEmptyFile(path$1.join(modelsDir, f)))) outdated = !isCurrentRevision(modelPath, formatEntry) && !await adoptByHash(modelsDir, modelPath, formatEntry);
|
|
569
|
+
else if (isCurrentRevision(modelPath, formatEntry) || await adoptByHash(modelsDir, modelPath, formatEntry)) return modelPath;
|
|
570
|
+
else outdated = true;
|
|
276
571
|
fs.mkdirSync(modelsDir, { recursive: true });
|
|
277
572
|
if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
|
|
573
|
+
else if (outdated) await replaceSingleFileFormat(formatEntry.url, modelPath, modelsDir, siblings, onProgress);
|
|
278
574
|
else {
|
|
279
575
|
await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
|
|
280
576
|
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), path$1.join(modelsDir, sibling));
|
|
281
577
|
}
|
|
578
|
+
writeRevisionRecord(modelPath, resolveFormatRevision(formatEntry));
|
|
282
579
|
return modelPath;
|
|
283
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Walk `entries` and record the revision of every complete copy on disk that
|
|
583
|
+
* hashes to it, so a node's listing reports present models as downloaded
|
|
584
|
+
* without waiting for something to `ensureModel` them. Offline: it reads
|
|
585
|
+
* files and never fetches. A copy already recorded current is not re-hashed.
|
|
586
|
+
*/
|
|
587
|
+
async function adoptModelRevisions(modelsDir, entries) {
|
|
588
|
+
const adopted = [];
|
|
589
|
+
const stale = [];
|
|
590
|
+
const seen = /* @__PURE__ */ new Set();
|
|
591
|
+
for (const entry of entries) for (const format of Object.keys(entry.formats).filter(isModelFormat)) {
|
|
592
|
+
const formatEntry = entry.formats[format];
|
|
593
|
+
if (formatEntry === void 0 || resolveFormatRevision(formatEntry) === void 0) continue;
|
|
594
|
+
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
595
|
+
if (modelPath === null || seen.has(modelPath)) continue;
|
|
596
|
+
seen.add(modelPath);
|
|
597
|
+
if (!isCompleteCopy(modelsDir, modelPath, formatEntry)) continue;
|
|
598
|
+
if (isCurrentRevision(modelPath, formatEntry)) continue;
|
|
599
|
+
const key = `${entry.id}/${format}`;
|
|
600
|
+
if (await adoptByHash(modelsDir, modelPath, formatEntry)) adopted.push(key);
|
|
601
|
+
else stale.push(key);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
adopted,
|
|
605
|
+
stale
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
function isModelFormat(value) {
|
|
609
|
+
return MODEL_FORMATS.some((f) => f === value);
|
|
610
|
+
}
|
|
284
611
|
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
285
612
|
function getModelFilePath(modelsDir, entry, format) {
|
|
286
613
|
const formatEntry = entry.formats[format];
|
|
@@ -288,20 +615,26 @@ function getModelFilePath(modelsDir, entry, format) {
|
|
|
288
615
|
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
289
616
|
return path$1.join(modelsDir, filename);
|
|
290
617
|
}
|
|
291
|
-
/**
|
|
618
|
+
/**
|
|
619
|
+
* True iff the model file (or `Manifest.json` for directory bundles) exists and
|
|
620
|
+
* is non-empty, and — when the format has a revision ({@link
|
|
621
|
+
* resolveFormatRevision}) — the node recorded that same revision for it
|
|
622
|
+
* (D743). Synchronous, so it never hashes: a copy not yet proven current
|
|
623
|
+
* answers false until `ensureModel` or {@link adoptModelRevisions} records it.
|
|
624
|
+
*/
|
|
292
625
|
function isModelDownloaded(modelsDir, entry, format) {
|
|
293
626
|
const formatEntry = entry.formats[format];
|
|
294
627
|
if (!formatEntry) return false;
|
|
295
628
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
296
629
|
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(modelsDir, f)));
|
|
630
|
+
if (!isCurrentRevision(modelPath, formatEntry)) return false;
|
|
631
|
+
return isCompleteCopy(modelsDir, modelPath, formatEntry);
|
|
300
632
|
}
|
|
301
633
|
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
302
634
|
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
303
635
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
304
636
|
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
637
|
+
fs.rmSync(revisionRecordPath(modelPath), { force: true });
|
|
305
638
|
const formatEntry = entry.formats[format];
|
|
306
639
|
if (formatEntry?.isDirectory) fs.rmSync(modelPath, {
|
|
307
640
|
recursive: true,
|
|
@@ -319,11 +652,13 @@ function deleteModelFromDisk(modelsDir, entry, format) {
|
|
|
319
652
|
//#endregion
|
|
320
653
|
//#region src/download/model-download-service.ts
|
|
321
654
|
/**
|
|
322
|
-
*
|
|
655
|
+
* A catalog-bound face over the shared downloader.
|
|
323
656
|
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
657
|
+
* Downloading, completeness and the revision contract (D743) are
|
|
658
|
+
* `ensureModel` / `isModelDownloaded`'s — this class only resolves a model id
|
|
659
|
+
* (and a default format) against its catalog and keys progress by model id.
|
|
660
|
+
* It used to carry its own copy of the download loop, which never learnt the
|
|
661
|
+
* revision; one rule now lives in one place.
|
|
327
662
|
*
|
|
328
663
|
* Addons use this via `context.models.ensure(modelId, format)`.
|
|
329
664
|
*/
|
|
@@ -339,33 +674,16 @@ var ModelDownloadService = class {
|
|
|
339
674
|
this.catalog = map;
|
|
340
675
|
}
|
|
341
676
|
/**
|
|
342
|
-
* Ensure a model (and its extra files) is downloaded.
|
|
677
|
+
* Ensure a model (and its extra files) is downloaded and current.
|
|
343
678
|
* Returns the local filesystem path to the model file/directory.
|
|
344
679
|
*/
|
|
345
680
|
async ensure(modelId, format) {
|
|
346
681
|
const entry = this.catalog.get(modelId);
|
|
347
682
|
if (!entry) throw new Error(`ModelDownloadService: unknown model "${modelId}"`);
|
|
348
683
|
const selectedFormat = format ?? this.pickDefaultFormat(entry);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
353
|
-
const siblings = siblingFilesFor(formatEntry);
|
|
354
|
-
if (fs.existsSync(modelPath)) {
|
|
355
|
-
if (formatEntry.isDirectory) if (!fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
|
|
356
|
-
recursive: true,
|
|
357
|
-
force: true
|
|
358
|
-
});
|
|
359
|
-
else return modelPath;
|
|
360
|
-
else if (siblings.every((f) => isNonEmptyFile(path$1.join(this.modelsDir, f)))) return modelPath;
|
|
361
|
-
}
|
|
362
|
-
fs.mkdirSync(this.modelsDir, { recursive: true });
|
|
363
|
-
if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
|
|
364
|
-
else {
|
|
365
|
-
await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
|
|
366
|
-
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), path$1.join(this.modelsDir, sibling));
|
|
367
|
-
}
|
|
368
|
-
return modelPath;
|
|
684
|
+
if (!entry.formats[selectedFormat]) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
|
|
685
|
+
const onProgress = this.onProgress;
|
|
686
|
+
return ensureModel(this.modelsDir, entry, selectedFormat, onProgress ? (downloaded, total) => onProgress(modelId, downloaded, total ?? 0) : void 0);
|
|
369
687
|
}
|
|
370
688
|
/**
|
|
371
689
|
* Ensure extra files for a model are downloaded.
|
|
@@ -388,18 +706,11 @@ var ModelDownloadService = class {
|
|
|
388
706
|
getModelsDir() {
|
|
389
707
|
return this.modelsDir;
|
|
390
708
|
}
|
|
391
|
-
/**
|
|
709
|
+
/** True when the model is on disk, complete, and at its revision (D743). */
|
|
392
710
|
isDownloaded(modelId, format) {
|
|
393
711
|
const entry = this.catalog.get(modelId);
|
|
394
712
|
if (!entry) return false;
|
|
395
|
-
|
|
396
|
-
const formatEntry = entry.formats[selectedFormat];
|
|
397
|
-
if (!formatEntry) return false;
|
|
398
|
-
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
399
|
-
if (!fs.existsSync(modelPath)) return false;
|
|
400
|
-
if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
|
|
401
|
-
if (fs.statSync(modelPath).size <= 0) return false;
|
|
402
|
-
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(this.modelsDir, f)));
|
|
713
|
+
return isModelDownloaded(this.modelsDir, entry, format ?? this.pickDefaultFormat(entry));
|
|
403
714
|
}
|
|
404
715
|
/** Get the catalog entry for a model by ID. */
|
|
405
716
|
getEntry(modelId) {
|
|
@@ -417,73 +728,6 @@ var ModelDownloadService = class {
|
|
|
417
728
|
if (first) return first;
|
|
418
729
|
throw new Error(`ModelDownloadService: model "${entry.id}" has no formats`);
|
|
419
730
|
}
|
|
420
|
-
modelFilePath(entry, format) {
|
|
421
|
-
const formatEntry = entry.formats[format];
|
|
422
|
-
if (!formatEntry) throw new Error(`Model ${entry.id} has no ${format} format`);
|
|
423
|
-
const urlParts = formatEntry.url.split("/");
|
|
424
|
-
const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`;
|
|
425
|
-
return path$1.join(this.modelsDir, filename);
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Download a directory bundle (e.g., .mlpackage) from HuggingFace.
|
|
429
|
-
* ATOMIC: downloads to temp dir, renames only on complete success.
|
|
430
|
-
*/
|
|
431
|
-
async downloadDirectory(url, destDir, knownFiles, _modelId) {
|
|
432
|
-
const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
|
|
433
|
-
if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
|
|
434
|
-
const [, repo, dirPath] = match;
|
|
435
|
-
let filesToDownload;
|
|
436
|
-
if (knownFiles && knownFiles.length > 0) filesToDownload = knownFiles.map((f) => ({
|
|
437
|
-
relativePath: f,
|
|
438
|
-
fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
|
|
439
|
-
}));
|
|
440
|
-
else {
|
|
441
|
-
const hfFiles = await this.listHfFiles(repo, dirPath);
|
|
442
|
-
if (hfFiles.length === 0) throw new Error(`No files found in HuggingFace directory: ${dirPath}`);
|
|
443
|
-
filesToDownload = hfFiles.map((f) => ({
|
|
444
|
-
relativePath: f.path.substring(dirPath.length + 1),
|
|
445
|
-
fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`
|
|
446
|
-
}));
|
|
447
|
-
}
|
|
448
|
-
const tmpDir = destDir + ".downloading";
|
|
449
|
-
fs.rmSync(tmpDir, {
|
|
450
|
-
recursive: true,
|
|
451
|
-
force: true
|
|
452
|
-
});
|
|
453
|
-
fs.mkdirSync(tmpDir, { recursive: true });
|
|
454
|
-
try {
|
|
455
|
-
for (const file of filesToDownload) {
|
|
456
|
-
const destPath = path$1.join(tmpDir, file.relativePath);
|
|
457
|
-
fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
|
|
458
|
-
await downloadFile(file.fileUrl, destPath);
|
|
459
|
-
}
|
|
460
|
-
fs.rmSync(destDir, {
|
|
461
|
-
recursive: true,
|
|
462
|
-
force: true
|
|
463
|
-
});
|
|
464
|
-
fs.renameSync(tmpDir, destDir);
|
|
465
|
-
} catch (err) {
|
|
466
|
-
fs.rmSync(tmpDir, {
|
|
467
|
-
recursive: true,
|
|
468
|
-
force: true
|
|
469
|
-
});
|
|
470
|
-
throw err;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
/** Recursively list all files in a HuggingFace directory via API. */
|
|
474
|
-
async listHfFiles(repo, dirPath) {
|
|
475
|
-
const entries = await fetchJson(`https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`);
|
|
476
|
-
const files = [];
|
|
477
|
-
for (const entry of entries) if (entry.type === "file") files.push({
|
|
478
|
-
path: entry.path,
|
|
479
|
-
size: entry.size ?? entry.lfs?.size ?? 0
|
|
480
|
-
});
|
|
481
|
-
else if (entry.type === "directory") {
|
|
482
|
-
const subFiles = await this.listHfFiles(repo, entry.path);
|
|
483
|
-
files.push(...subFiles);
|
|
484
|
-
}
|
|
485
|
-
return files;
|
|
486
|
-
}
|
|
487
731
|
};
|
|
488
732
|
//#endregion
|
|
489
733
|
//#region src/http/authenticated-file-server.ts
|
|
@@ -1133,4 +1377,4 @@ function startEventLoopStallMonitor(logger, reportThresholdMs = STALL_REPORT_MS)
|
|
|
1133
1377
|
};
|
|
1134
1378
|
}
|
|
1135
1379
|
//#endregion
|
|
1136
|
-
export {
|
|
1380
|
+
export { resolveFormatRevision as C, isModelDownloaded as S, downloadModel as _, createFileDataPlaneHandler as a, getModelFilePath as b, parseRangeHeader as c, ModelDownloadService as d, ModelDownloadHttpError as f, downloadFile as g, deleteModelFromDisk as h, startEventLoopStallMonitor as i, parseTokenizedUrl as l, collectModelFiles as m, STALL_TICK_MS as n, contentTypeFor as o, adoptModelRevisions as p, attributeStall as r, createAuthenticatedFileServer as s, STALL_REPORT_MS as t, resolveFilePath as u, ensureModel as v, revisionWeightUrl as w, isModelDownloadHttpError as x, fetchJson as y };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,8 +39,8 @@ export { StorageOrchestratorAddon, StorageOrchestratorService, } from './builtin
|
|
|
39
39
|
export { SystemConfigAddon } from './builtins/system-config/index.js';
|
|
40
40
|
export { WinstonDestination, WinstonLoggingAddon } from './builtins/winston-logging/index.js';
|
|
41
41
|
export { ModelDownloadService } from './download/model-download-service.js';
|
|
42
|
-
export type { DownloadProgressCallback } from './download/model-downloader.js';
|
|
43
|
-
export { collectModelFiles, deleteModelFromDisk, downloadFile, downloadModel, ensureModel, fetchJson, getModelFilePath, isModelDownloaded, } from './download/model-downloader.js';
|
|
42
|
+
export type { DownloadProgressCallback, ModelRevisionAdoption, RevisionWeightFile, } from './download/model-downloader.js';
|
|
43
|
+
export { adoptModelRevisions, collectModelFiles, deleteModelFromDisk, downloadFile, downloadModel, ensureModel, fetchJson, getModelFilePath, isModelDownloaded, resolveFormatRevision, revisionWeightUrl, } from './download/model-downloader.js';
|
|
44
44
|
export { EventBus } from './events/event-bus.js';
|
|
45
45
|
export type { EventFilter, EventSource, SystemEvent, } from './events/system-event-bus.js';
|
|
46
46
|
export { SystemEventBus } from './events/system-event-bus.js';
|