@camstack/addon-pipeline 1.1.65 → 1.1.67
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/audio-analyzer/index.js +1 -1
- package/dist/audio-analyzer/index.mjs +1 -1
- package/dist/detection-pipeline/index.js +83 -22
- package/dist/detection-pipeline/index.mjs +83 -22
- package/dist/{dist-WW3gH8hF.js → dist-BxxVKcnw.js} +56 -5
- package/dist/{dist-D6tHM9GA.mjs → dist-DkGHtAaK.mjs} +56 -5
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +88 -22
- package/dist/pipeline-runner/index.mjs +88 -22
- package/dist/recorder/index.js +141 -1
- package/dist/recorder/index.mjs +141 -1
- package/dist/session-decode/decode-worker-child.js +185 -14
- package/dist/session-decode/decode-worker-child.mjs +185 -14
- package/dist/{step-definitions-CXZpwwT0.js → step-definitions-CAs0RD2N.js} +127 -8
- package/dist/{step-definitions-Dbsm64_I.mjs → step-definitions-Delhq28w.mjs} +127 -8
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CbU_HuOC.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CfFsU700.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D68Lj69v.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DlALQ_wp.mjs +26 -0
- package/dist/stream-broker/{hostInit-QaDEOY0Z.mjs → hostInit-D-S5fCDx.mjs} +2 -2
- package/dist/stream-broker/index.js +1 -1
- package/dist/stream-broker/index.mjs +1 -1
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-C7H0kVAH.js → MaskShapeCanvas-DI4BY7W2-CRvzj7Of.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-CHfEFlEF.js → MotionZonesSettings-NcxxQN8r-CBgvPUB-.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-Bc-trVxX.js → PrivacyMaskSettings-APgPLF7p-DH07fe1k.js} +1 -1
- package/embed-dist/assets/index-BkoPcGtQ.js +114 -0
- package/embed-dist/assets/index-D2pF9Z3W.css +2 -0
- package/embed-dist/index.html +2 -2
- package/package.json +1 -1
- package/python/inference_pool.py +392 -45
- package/python/postprocessors/softmax.py +17 -5
- package/python/postprocessors/test_softmax.py +52 -0
- package/python/test_inference_pool_ov_ppp.py +117 -0
- package/python/test_inference_pool_preprocess.py +93 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CxZvj8X1.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BzNJyeNE.mjs +0 -26
- package/embed-dist/assets/index-Bm9LaQPH.css +0 -2
- package/embed-dist/assets/index-eZGm_itM.js +0 -81
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-D6vf50IK.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
6
|
+
const require_dist = require("../dist-BxxVKcnw.js");
|
|
7
7
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
8
8
|
const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
|
|
9
9
|
let node_fs = require("node:fs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __require } from "../chunk-BdkLduGY.mjs";
|
|
2
|
-
import { B as errMsg, K as hydrateSchema, T as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalyzerCapability, g as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL } from "../dist-
|
|
2
|
+
import { B as errMsg, K as hydrateSchema, T as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalyzerCapability, g as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL } from "../dist-DkGHtAaK.mjs";
|
|
3
3
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
4
4
|
import { i as downloadFile } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
|
|
5
5
|
import * as fs from "node:fs";
|
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-D6vf50IK.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_step_definitions = require("../step-definitions-
|
|
6
|
+
const require_dist = require("../dist-BxxVKcnw.js");
|
|
7
|
+
const require_step_definitions = require("../step-definitions-CAs0RD2N.js");
|
|
8
8
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
9
9
|
const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
|
|
10
10
|
let node_child_process = require("node:child_process");
|
|
@@ -426,6 +426,15 @@ var RAW_FMT_CODE = {
|
|
|
426
426
|
bgr: 1,
|
|
427
427
|
gray: 2
|
|
428
428
|
};
|
|
429
|
+
/**
|
|
430
|
+
* Per-inference-request reply timeout (ms). Turns a wedged request (worker
|
|
431
|
+
* alive but no reply) into a rejection so every caller settles — runtime frame
|
|
432
|
+
* dispatch drops the frame; the benchmark full-tree run rejects the wedged
|
|
433
|
+
* child (its enclosing try/catch keeps the root detections) instead of hanging
|
|
434
|
+
* the UI on "loading" forever. Generous so legitimate slow inference (cold JIT,
|
|
435
|
+
* large frame) never trips; override via env for constrained hardware.
|
|
436
|
+
*/
|
|
437
|
+
var POOL_INFER_TIMEOUT_MS = Math.max(1e3, Number(process.env["CAMSTACK_POOL_INFER_TIMEOUT_MS"]) || 6e4);
|
|
429
438
|
var PoolHandle = class {
|
|
430
439
|
pool;
|
|
431
440
|
modelIndex;
|
|
@@ -608,15 +617,16 @@ var PoolWorker = class {
|
|
|
608
617
|
rawHeader[9] = fmtCode;
|
|
609
618
|
return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw]);
|
|
610
619
|
}
|
|
611
|
-
async inferBatch(modelByte, items) {
|
|
620
|
+
async inferBatch(modelByte, items, frameId = 0) {
|
|
612
621
|
this.ensureReady();
|
|
613
622
|
if (items.length === 0) return [];
|
|
614
|
-
const headerSize =
|
|
623
|
+
const headerSize = 6 + items.length * 13;
|
|
615
624
|
const totalRawSize = items.reduce((sum, it) => sum + it.raw.length, 0);
|
|
616
625
|
const payload = Buffer.allocUnsafe(headerSize + totalRawSize);
|
|
617
626
|
payload[0] = modelByte;
|
|
618
627
|
payload[1] = items.length;
|
|
619
|
-
|
|
628
|
+
payload.writeUInt32LE(frameId >>> 0, 2);
|
|
629
|
+
let offset = 6;
|
|
620
630
|
for (const item of items) {
|
|
621
631
|
payload.writeUInt32LE(item.width, offset);
|
|
622
632
|
payload.writeUInt32LE(item.height, offset + 4);
|
|
@@ -665,24 +675,48 @@ var PoolWorker = class {
|
|
|
665
675
|
dispatch(msgType, payload) {
|
|
666
676
|
const reqId = this.allocRequestId();
|
|
667
677
|
return new Promise((resolve, reject) => {
|
|
678
|
+
const timer = this.armRequestTimeout(reqId, reject);
|
|
668
679
|
this.pending.set(reqId, {
|
|
669
680
|
resolve,
|
|
670
|
-
reject
|
|
681
|
+
reject,
|
|
682
|
+
timer
|
|
671
683
|
});
|
|
672
684
|
try {
|
|
673
685
|
this.writeFrame(reqId, msgType, payload);
|
|
674
686
|
} catch (err) {
|
|
687
|
+
clearTimeout(timer);
|
|
675
688
|
this.pending.delete(reqId);
|
|
676
689
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
677
690
|
}
|
|
678
691
|
});
|
|
679
692
|
}
|
|
693
|
+
/**
|
|
694
|
+
* Arm a watchdog that rejects a still-pending inference request after
|
|
695
|
+
* `POOL_INFER_TIMEOUT_MS`. `unref` so it never keeps the event loop alive.
|
|
696
|
+
* The normal response + `rejectAll` paths clear it via `PendingRequest.timer`.
|
|
697
|
+
*/
|
|
698
|
+
armRequestTimeout(reqId, reject) {
|
|
699
|
+
const timer = setTimeout(() => {
|
|
700
|
+
if (this.pending.delete(reqId)) {
|
|
701
|
+
this.log.error("inference request timed out", { meta: {
|
|
702
|
+
worker: this.opts.workerLabel,
|
|
703
|
+
reqId,
|
|
704
|
+
timeoutMs: POOL_INFER_TIMEOUT_MS
|
|
705
|
+
} });
|
|
706
|
+
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${POOL_INFER_TIMEOUT_MS}ms (worker alive, no reply)`));
|
|
707
|
+
}
|
|
708
|
+
}, POOL_INFER_TIMEOUT_MS);
|
|
709
|
+
timer.unref?.();
|
|
710
|
+
return timer;
|
|
711
|
+
}
|
|
680
712
|
dispatchMulti(msgType, payloadLen, parts) {
|
|
681
713
|
const reqId = this.allocRequestId();
|
|
682
714
|
return new Promise((resolve, reject) => {
|
|
715
|
+
const timer = this.armRequestTimeout(reqId, reject);
|
|
683
716
|
this.pending.set(reqId, {
|
|
684
717
|
resolve,
|
|
685
|
-
reject
|
|
718
|
+
reject,
|
|
719
|
+
timer
|
|
686
720
|
});
|
|
687
721
|
try {
|
|
688
722
|
if (!this.process?.stdin) throw new Error("PoolWorker: not initialized");
|
|
@@ -693,6 +727,7 @@ var PoolWorker = class {
|
|
|
693
727
|
this.process.stdin.write(prefix);
|
|
694
728
|
for (const part of parts) this.process.stdin.write(part);
|
|
695
729
|
} catch (err) {
|
|
730
|
+
clearTimeout(timer);
|
|
696
731
|
this.pending.delete(reqId);
|
|
697
732
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
698
733
|
}
|
|
@@ -736,6 +771,7 @@ var PoolWorker = class {
|
|
|
736
771
|
continue;
|
|
737
772
|
}
|
|
738
773
|
this.pending.delete(reqId);
|
|
774
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
739
775
|
try {
|
|
740
776
|
const parsed = JSON.parse(jsonBytes.toString("utf8"));
|
|
741
777
|
entry.resolve(parsed);
|
|
@@ -747,7 +783,10 @@ var PoolWorker = class {
|
|
|
747
783
|
rejectAll(err) {
|
|
748
784
|
const entries = [...this.pending.values()];
|
|
749
785
|
this.pending.clear();
|
|
750
|
-
for (const entry of entries)
|
|
786
|
+
for (const entry of entries) {
|
|
787
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
788
|
+
entry.reject(err);
|
|
789
|
+
}
|
|
751
790
|
}
|
|
752
791
|
};
|
|
753
792
|
var SharedInferencePool = class {
|
|
@@ -827,9 +866,9 @@ var SharedInferencePool = class {
|
|
|
827
866
|
const w = this.pickWorker();
|
|
828
867
|
return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format), modelIndex);
|
|
829
868
|
}
|
|
830
|
-
async inferBatch(modelIndex, items) {
|
|
869
|
+
async inferBatch(modelIndex, items, frameId = 0) {
|
|
831
870
|
if (items.length > 255) throw new Error(`SharedInferencePool.inferBatch: max 255 items per call, got ${items.length}`);
|
|
832
|
-
return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items);
|
|
871
|
+
return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items, frameId);
|
|
833
872
|
}
|
|
834
873
|
async inferCached(modelIndex, frameId) {
|
|
835
874
|
const w = this.pickWorker();
|
|
@@ -952,6 +991,8 @@ function serializeModelConfig(config) {
|
|
|
952
991
|
confidence: config.confidence
|
|
953
992
|
};
|
|
954
993
|
if (config.nmsIouThreshold !== void 0) result["nmsIouThreshold"] = config.nmsIouThreshold;
|
|
994
|
+
if (config.inputNormalization !== void 0) result["inputNormalization"] = config.inputNormalization;
|
|
995
|
+
if (config.outputProbabilities !== void 0) result["outputProbabilities"] = config.outputProbabilities;
|
|
955
996
|
if (config.inputWidth !== void 0) result["inputWidth"] = config.inputWidth;
|
|
956
997
|
if (config.inputHeight !== void 0) result["inputHeight"] = config.inputHeight;
|
|
957
998
|
if (config.inputChannels !== void 0) result["inputChannels"] = config.inputChannels;
|
|
@@ -1284,6 +1325,30 @@ var OBJECT_DETECTION_POOL_CONFIDENCE_FLOOR = .05;
|
|
|
1284
1325
|
function resolvePoolConfidenceFloor(stepId, defaultConfidence) {
|
|
1285
1326
|
return stepId === OBJECT_DETECTION_STEP_ID ? OBJECT_DETECTION_POOL_CONFIDENCE_FLOOR : defaultConfidence;
|
|
1286
1327
|
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Load a model's runtime label list from its `-labels.json` extraFile, if any.
|
|
1330
|
+
*
|
|
1331
|
+
* Accepts BOTH on-disk shapes:
|
|
1332
|
+
* - a flat `string[]` (legacy label files), and
|
|
1333
|
+
* - a `{ "labels": string[], ... }` metadata object (the newer format the
|
|
1334
|
+
* animal / bird / vehicle classifiers ship, which also carries preprocess /
|
|
1335
|
+
* license metadata alongside the label array).
|
|
1336
|
+
*
|
|
1337
|
+
* Returns `undefined` when the model declares no `-labels.json`, the file is
|
|
1338
|
+
* absent, or its contents are not a recognised label shape — the caller then
|
|
1339
|
+
* falls back to the step's `def.labels`.
|
|
1340
|
+
*/
|
|
1341
|
+
var LabelsFileSchema = require_dist.union([require_dist.array(require_dist.string()).readonly(), require_dist.object({ labels: require_dist.array(require_dist.string()).readonly() })]);
|
|
1342
|
+
function readModelLabels(modelsDir, modelEntry) {
|
|
1343
|
+
const labelsFile = modelEntry.extraFiles?.find((f) => f.filename.endsWith("-labels.json"));
|
|
1344
|
+
if (!labelsFile) return void 0;
|
|
1345
|
+
const labelsPath = node_path.join(modelsDir, labelsFile.filename);
|
|
1346
|
+
if (!node_fs.existsSync(labelsPath)) return void 0;
|
|
1347
|
+
const parsed = LabelsFileSchema.safeParse(JSON.parse(node_fs.readFileSync(labelsPath, "utf8")));
|
|
1348
|
+
if (!parsed.success) return void 0;
|
|
1349
|
+
const data = parsed.data;
|
|
1350
|
+
return "labels" in data ? data.labels : data;
|
|
1351
|
+
}
|
|
1287
1352
|
var EngineFactory = class {
|
|
1288
1353
|
pool = null;
|
|
1289
1354
|
poolManager = null;
|
|
@@ -1361,11 +1426,11 @@ var EngineFactory = class {
|
|
|
1361
1426
|
* Used by `runPipelineBatch` for fair batched benchmarking — N frames
|
|
1362
1427
|
* in one IPC round-trip, amortising the per-call envelope overhead.
|
|
1363
1428
|
*/
|
|
1364
|
-
async batchInferRaw(stepId, items, modelId) {
|
|
1429
|
+
async batchInferRaw(stepId, items, modelId, frameId = 0) {
|
|
1365
1430
|
if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool not initialized");
|
|
1366
1431
|
const idx = this.poolManager.getPoolIndex(stepId, modelId);
|
|
1367
1432
|
if (idx === null) throw new Error(`EngineFactory.batchInferRaw: step "${stepId}"${modelId ? ` (model "${modelId}")` : ""} is not loaded`);
|
|
1368
|
-
return this.poolManager.getPool().inferBatch(idx, items);
|
|
1433
|
+
return this.poolManager.getPool().inferBatch(idx, items, frameId);
|
|
1369
1434
|
}
|
|
1370
1435
|
async cacheFrameInPool(raw, width, height, format) {
|
|
1371
1436
|
if (!this.poolManager) throw new Error("cacheFrameInPool: pool not available");
|
|
@@ -1451,14 +1516,7 @@ var EngineFactory = class {
|
|
|
1451
1516
|
const inputHeight = modelEntry.inputSize.height;
|
|
1452
1517
|
const inputSize = Math.max(inputWidth, inputHeight);
|
|
1453
1518
|
const inputChannels = modelEntry.inputChannels ?? 3;
|
|
1454
|
-
|
|
1455
|
-
if (!labels && modelEntry.extraFiles) {
|
|
1456
|
-
const labelsFile = modelEntry.extraFiles.find((f) => f.filename.endsWith("-labels.json"));
|
|
1457
|
-
if (labelsFile) {
|
|
1458
|
-
const labelsPath = node_path.join(this.opts.modelsDir, labelsFile.filename);
|
|
1459
|
-
if (node_fs.existsSync(labelsPath)) labels = JSON.parse(node_fs.readFileSync(labelsPath, "utf8"));
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1519
|
+
const labels = readModelLabels(this.opts.modelsDir, modelEntry) ?? def.labels;
|
|
1462
1520
|
return {
|
|
1463
1521
|
path: modelPath,
|
|
1464
1522
|
inputSize,
|
|
@@ -1466,6 +1524,8 @@ var EngineFactory = class {
|
|
|
1466
1524
|
inputHeight,
|
|
1467
1525
|
inputChannels,
|
|
1468
1526
|
preprocessMode: modelEntry.preprocessMode ?? "letterbox",
|
|
1527
|
+
inputNormalization: modelEntry.inputNormalization,
|
|
1528
|
+
outputProbabilities: modelEntry.outputProbabilities,
|
|
1469
1529
|
postprocessor: modelEntry.postprocessor ?? def.postprocessor,
|
|
1470
1530
|
confidence: resolvePoolConfidenceFloor(stepId, def.defaultConfidence),
|
|
1471
1531
|
nmsIouThreshold: this.opts.nmsIouThreshold ?? .45,
|
|
@@ -2584,7 +2644,8 @@ function applyChildOutput(parent, childStep, output, stepLatencyMs, ctx) {
|
|
|
2584
2644
|
case "classifications": {
|
|
2585
2645
|
const rawEnabled = childStep.settings?.["enabledClasses"];
|
|
2586
2646
|
const enabledSet = Array.isArray(rawEnabled) && rawEnabled.length > 0 ? new Set(rawEnabled.filter((v) => typeof v === "string")) : null;
|
|
2587
|
-
const
|
|
2647
|
+
const rejectSet = childStep.definition.rejectClasses && childStep.definition.rejectClasses.length > 0 ? new Set(childStep.definition.rejectClasses.map((c) => c.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
2648
|
+
const passesClass = (c) => (enabledSet === null || enabledSet.has(c.class)) && !rejectSet.has(c.class.toLowerCase());
|
|
2588
2649
|
const minConfidence = typeof childStep.settings?.["minConfidence"] === "number" ? childStep.settings["minConfidence"] : 0;
|
|
2589
2650
|
const winner = output.classifications[0];
|
|
2590
2651
|
if (winner && passesClass(winner) && winner.score >= minConfidence) parent.ownLabels.push({
|
|
@@ -5551,7 +5612,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
5551
5612
|
totalRawBytes: items.reduce((s, it) => s + it.raw.length, 0)
|
|
5552
5613
|
} });
|
|
5553
5614
|
const start = performance.now();
|
|
5554
|
-
const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId);
|
|
5615
|
+
const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId, input.frameId ?? 0);
|
|
5555
5616
|
const totalMs = performance.now() - start;
|
|
5556
5617
|
this.log.info("runPipelineBatch fast path returned", { meta: {
|
|
5557
5618
|
phase: "batch",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __require } from "../chunk-BdkLduGY.mjs";
|
|
2
|
-
import { $ as sleep, A as pipelineExecutorCapability, B as errMsg, C as evaluateZoneRules, F as runtimeDevices$1, G as createEvent, K as hydrateSchema, R as supportedRuntimes$1, S as detectionPipelineCapability, V as BaseAddon, X as parseJsonUnknown, b as defaultDeviceFor$1, dt as EventCategory, k as nodePin, m as YAMNET_TO_MACRO, t as APPLE_SA_TO_MACRO } from "../dist-
|
|
3
|
-
import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-
|
|
2
|
+
import { $ as sleep, A as pipelineExecutorCapability, B as errMsg, C as evaluateZoneRules, F as runtimeDevices$1, G as createEvent, K as hydrateSchema, R as supportedRuntimes$1, S as detectionPipelineCapability, V as BaseAddon, X as parseJsonUnknown, b as defaultDeviceFor$1, dt as EventCategory, k as nodePin, lt as string, m as YAMNET_TO_MACRO, st as object, t as APPLE_SA_TO_MACRO, tt as array, ut as union } from "../dist-DkGHtAaK.mjs";
|
|
3
|
+
import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-Delhq28w.mjs";
|
|
4
4
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
5
5
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
@@ -418,6 +418,15 @@ var RAW_FMT_CODE = {
|
|
|
418
418
|
bgr: 1,
|
|
419
419
|
gray: 2
|
|
420
420
|
};
|
|
421
|
+
/**
|
|
422
|
+
* Per-inference-request reply timeout (ms). Turns a wedged request (worker
|
|
423
|
+
* alive but no reply) into a rejection so every caller settles — runtime frame
|
|
424
|
+
* dispatch drops the frame; the benchmark full-tree run rejects the wedged
|
|
425
|
+
* child (its enclosing try/catch keeps the root detections) instead of hanging
|
|
426
|
+
* the UI on "loading" forever. Generous so legitimate slow inference (cold JIT,
|
|
427
|
+
* large frame) never trips; override via env for constrained hardware.
|
|
428
|
+
*/
|
|
429
|
+
var POOL_INFER_TIMEOUT_MS = Math.max(1e3, Number(process.env["CAMSTACK_POOL_INFER_TIMEOUT_MS"]) || 6e4);
|
|
421
430
|
var PoolHandle = class {
|
|
422
431
|
pool;
|
|
423
432
|
modelIndex;
|
|
@@ -600,15 +609,16 @@ var PoolWorker = class {
|
|
|
600
609
|
rawHeader[9] = fmtCode;
|
|
601
610
|
return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw]);
|
|
602
611
|
}
|
|
603
|
-
async inferBatch(modelByte, items) {
|
|
612
|
+
async inferBatch(modelByte, items, frameId = 0) {
|
|
604
613
|
this.ensureReady();
|
|
605
614
|
if (items.length === 0) return [];
|
|
606
|
-
const headerSize =
|
|
615
|
+
const headerSize = 6 + items.length * 13;
|
|
607
616
|
const totalRawSize = items.reduce((sum, it) => sum + it.raw.length, 0);
|
|
608
617
|
const payload = Buffer.allocUnsafe(headerSize + totalRawSize);
|
|
609
618
|
payload[0] = modelByte;
|
|
610
619
|
payload[1] = items.length;
|
|
611
|
-
|
|
620
|
+
payload.writeUInt32LE(frameId >>> 0, 2);
|
|
621
|
+
let offset = 6;
|
|
612
622
|
for (const item of items) {
|
|
613
623
|
payload.writeUInt32LE(item.width, offset);
|
|
614
624
|
payload.writeUInt32LE(item.height, offset + 4);
|
|
@@ -657,24 +667,48 @@ var PoolWorker = class {
|
|
|
657
667
|
dispatch(msgType, payload) {
|
|
658
668
|
const reqId = this.allocRequestId();
|
|
659
669
|
return new Promise((resolve, reject) => {
|
|
670
|
+
const timer = this.armRequestTimeout(reqId, reject);
|
|
660
671
|
this.pending.set(reqId, {
|
|
661
672
|
resolve,
|
|
662
|
-
reject
|
|
673
|
+
reject,
|
|
674
|
+
timer
|
|
663
675
|
});
|
|
664
676
|
try {
|
|
665
677
|
this.writeFrame(reqId, msgType, payload);
|
|
666
678
|
} catch (err) {
|
|
679
|
+
clearTimeout(timer);
|
|
667
680
|
this.pending.delete(reqId);
|
|
668
681
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
669
682
|
}
|
|
670
683
|
});
|
|
671
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* Arm a watchdog that rejects a still-pending inference request after
|
|
687
|
+
* `POOL_INFER_TIMEOUT_MS`. `unref` so it never keeps the event loop alive.
|
|
688
|
+
* The normal response + `rejectAll` paths clear it via `PendingRequest.timer`.
|
|
689
|
+
*/
|
|
690
|
+
armRequestTimeout(reqId, reject) {
|
|
691
|
+
const timer = setTimeout(() => {
|
|
692
|
+
if (this.pending.delete(reqId)) {
|
|
693
|
+
this.log.error("inference request timed out", { meta: {
|
|
694
|
+
worker: this.opts.workerLabel,
|
|
695
|
+
reqId,
|
|
696
|
+
timeoutMs: POOL_INFER_TIMEOUT_MS
|
|
697
|
+
} });
|
|
698
|
+
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${POOL_INFER_TIMEOUT_MS}ms (worker alive, no reply)`));
|
|
699
|
+
}
|
|
700
|
+
}, POOL_INFER_TIMEOUT_MS);
|
|
701
|
+
timer.unref?.();
|
|
702
|
+
return timer;
|
|
703
|
+
}
|
|
672
704
|
dispatchMulti(msgType, payloadLen, parts) {
|
|
673
705
|
const reqId = this.allocRequestId();
|
|
674
706
|
return new Promise((resolve, reject) => {
|
|
707
|
+
const timer = this.armRequestTimeout(reqId, reject);
|
|
675
708
|
this.pending.set(reqId, {
|
|
676
709
|
resolve,
|
|
677
|
-
reject
|
|
710
|
+
reject,
|
|
711
|
+
timer
|
|
678
712
|
});
|
|
679
713
|
try {
|
|
680
714
|
if (!this.process?.stdin) throw new Error("PoolWorker: not initialized");
|
|
@@ -685,6 +719,7 @@ var PoolWorker = class {
|
|
|
685
719
|
this.process.stdin.write(prefix);
|
|
686
720
|
for (const part of parts) this.process.stdin.write(part);
|
|
687
721
|
} catch (err) {
|
|
722
|
+
clearTimeout(timer);
|
|
688
723
|
this.pending.delete(reqId);
|
|
689
724
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
690
725
|
}
|
|
@@ -728,6 +763,7 @@ var PoolWorker = class {
|
|
|
728
763
|
continue;
|
|
729
764
|
}
|
|
730
765
|
this.pending.delete(reqId);
|
|
766
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
731
767
|
try {
|
|
732
768
|
const parsed = JSON.parse(jsonBytes.toString("utf8"));
|
|
733
769
|
entry.resolve(parsed);
|
|
@@ -739,7 +775,10 @@ var PoolWorker = class {
|
|
|
739
775
|
rejectAll(err) {
|
|
740
776
|
const entries = [...this.pending.values()];
|
|
741
777
|
this.pending.clear();
|
|
742
|
-
for (const entry of entries)
|
|
778
|
+
for (const entry of entries) {
|
|
779
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
780
|
+
entry.reject(err);
|
|
781
|
+
}
|
|
743
782
|
}
|
|
744
783
|
};
|
|
745
784
|
var SharedInferencePool = class {
|
|
@@ -819,9 +858,9 @@ var SharedInferencePool = class {
|
|
|
819
858
|
const w = this.pickWorker();
|
|
820
859
|
return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format), modelIndex);
|
|
821
860
|
}
|
|
822
|
-
async inferBatch(modelIndex, items) {
|
|
861
|
+
async inferBatch(modelIndex, items, frameId = 0) {
|
|
823
862
|
if (items.length > 255) throw new Error(`SharedInferencePool.inferBatch: max 255 items per call, got ${items.length}`);
|
|
824
|
-
return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items);
|
|
863
|
+
return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items, frameId);
|
|
825
864
|
}
|
|
826
865
|
async inferCached(modelIndex, frameId) {
|
|
827
866
|
const w = this.pickWorker();
|
|
@@ -944,6 +983,8 @@ function serializeModelConfig(config) {
|
|
|
944
983
|
confidence: config.confidence
|
|
945
984
|
};
|
|
946
985
|
if (config.nmsIouThreshold !== void 0) result["nmsIouThreshold"] = config.nmsIouThreshold;
|
|
986
|
+
if (config.inputNormalization !== void 0) result["inputNormalization"] = config.inputNormalization;
|
|
987
|
+
if (config.outputProbabilities !== void 0) result["outputProbabilities"] = config.outputProbabilities;
|
|
947
988
|
if (config.inputWidth !== void 0) result["inputWidth"] = config.inputWidth;
|
|
948
989
|
if (config.inputHeight !== void 0) result["inputHeight"] = config.inputHeight;
|
|
949
990
|
if (config.inputChannels !== void 0) result["inputChannels"] = config.inputChannels;
|
|
@@ -1276,6 +1317,30 @@ var OBJECT_DETECTION_POOL_CONFIDENCE_FLOOR = .05;
|
|
|
1276
1317
|
function resolvePoolConfidenceFloor(stepId, defaultConfidence) {
|
|
1277
1318
|
return stepId === OBJECT_DETECTION_STEP_ID ? OBJECT_DETECTION_POOL_CONFIDENCE_FLOOR : defaultConfidence;
|
|
1278
1319
|
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Load a model's runtime label list from its `-labels.json` extraFile, if any.
|
|
1322
|
+
*
|
|
1323
|
+
* Accepts BOTH on-disk shapes:
|
|
1324
|
+
* - a flat `string[]` (legacy label files), and
|
|
1325
|
+
* - a `{ "labels": string[], ... }` metadata object (the newer format the
|
|
1326
|
+
* animal / bird / vehicle classifiers ship, which also carries preprocess /
|
|
1327
|
+
* license metadata alongside the label array).
|
|
1328
|
+
*
|
|
1329
|
+
* Returns `undefined` when the model declares no `-labels.json`, the file is
|
|
1330
|
+
* absent, or its contents are not a recognised label shape — the caller then
|
|
1331
|
+
* falls back to the step's `def.labels`.
|
|
1332
|
+
*/
|
|
1333
|
+
var LabelsFileSchema = union([array(string()).readonly(), object({ labels: array(string()).readonly() })]);
|
|
1334
|
+
function readModelLabels(modelsDir, modelEntry) {
|
|
1335
|
+
const labelsFile = modelEntry.extraFiles?.find((f) => f.filename.endsWith("-labels.json"));
|
|
1336
|
+
if (!labelsFile) return void 0;
|
|
1337
|
+
const labelsPath = path$1.join(modelsDir, labelsFile.filename);
|
|
1338
|
+
if (!fs.existsSync(labelsPath)) return void 0;
|
|
1339
|
+
const parsed = LabelsFileSchema.safeParse(JSON.parse(fs.readFileSync(labelsPath, "utf8")));
|
|
1340
|
+
if (!parsed.success) return void 0;
|
|
1341
|
+
const data = parsed.data;
|
|
1342
|
+
return "labels" in data ? data.labels : data;
|
|
1343
|
+
}
|
|
1279
1344
|
var EngineFactory = class {
|
|
1280
1345
|
pool = null;
|
|
1281
1346
|
poolManager = null;
|
|
@@ -1353,11 +1418,11 @@ var EngineFactory = class {
|
|
|
1353
1418
|
* Used by `runPipelineBatch` for fair batched benchmarking — N frames
|
|
1354
1419
|
* in one IPC round-trip, amortising the per-call envelope overhead.
|
|
1355
1420
|
*/
|
|
1356
|
-
async batchInferRaw(stepId, items, modelId) {
|
|
1421
|
+
async batchInferRaw(stepId, items, modelId, frameId = 0) {
|
|
1357
1422
|
if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool not initialized");
|
|
1358
1423
|
const idx = this.poolManager.getPoolIndex(stepId, modelId);
|
|
1359
1424
|
if (idx === null) throw new Error(`EngineFactory.batchInferRaw: step "${stepId}"${modelId ? ` (model "${modelId}")` : ""} is not loaded`);
|
|
1360
|
-
return this.poolManager.getPool().inferBatch(idx, items);
|
|
1425
|
+
return this.poolManager.getPool().inferBatch(idx, items, frameId);
|
|
1361
1426
|
}
|
|
1362
1427
|
async cacheFrameInPool(raw, width, height, format) {
|
|
1363
1428
|
if (!this.poolManager) throw new Error("cacheFrameInPool: pool not available");
|
|
@@ -1443,14 +1508,7 @@ var EngineFactory = class {
|
|
|
1443
1508
|
const inputHeight = modelEntry.inputSize.height;
|
|
1444
1509
|
const inputSize = Math.max(inputWidth, inputHeight);
|
|
1445
1510
|
const inputChannels = modelEntry.inputChannels ?? 3;
|
|
1446
|
-
|
|
1447
|
-
if (!labels && modelEntry.extraFiles) {
|
|
1448
|
-
const labelsFile = modelEntry.extraFiles.find((f) => f.filename.endsWith("-labels.json"));
|
|
1449
|
-
if (labelsFile) {
|
|
1450
|
-
const labelsPath = path$1.join(this.opts.modelsDir, labelsFile.filename);
|
|
1451
|
-
if (fs.existsSync(labelsPath)) labels = JSON.parse(fs.readFileSync(labelsPath, "utf8"));
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1511
|
+
const labels = readModelLabels(this.opts.modelsDir, modelEntry) ?? def.labels;
|
|
1454
1512
|
return {
|
|
1455
1513
|
path: modelPath,
|
|
1456
1514
|
inputSize,
|
|
@@ -1458,6 +1516,8 @@ var EngineFactory = class {
|
|
|
1458
1516
|
inputHeight,
|
|
1459
1517
|
inputChannels,
|
|
1460
1518
|
preprocessMode: modelEntry.preprocessMode ?? "letterbox",
|
|
1519
|
+
inputNormalization: modelEntry.inputNormalization,
|
|
1520
|
+
outputProbabilities: modelEntry.outputProbabilities,
|
|
1461
1521
|
postprocessor: modelEntry.postprocessor ?? def.postprocessor,
|
|
1462
1522
|
confidence: resolvePoolConfidenceFloor(stepId, def.defaultConfidence),
|
|
1463
1523
|
nmsIouThreshold: this.opts.nmsIouThreshold ?? .45,
|
|
@@ -2576,7 +2636,8 @@ function applyChildOutput(parent, childStep, output, stepLatencyMs, ctx) {
|
|
|
2576
2636
|
case "classifications": {
|
|
2577
2637
|
const rawEnabled = childStep.settings?.["enabledClasses"];
|
|
2578
2638
|
const enabledSet = Array.isArray(rawEnabled) && rawEnabled.length > 0 ? new Set(rawEnabled.filter((v) => typeof v === "string")) : null;
|
|
2579
|
-
const
|
|
2639
|
+
const rejectSet = childStep.definition.rejectClasses && childStep.definition.rejectClasses.length > 0 ? new Set(childStep.definition.rejectClasses.map((c) => c.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
2640
|
+
const passesClass = (c) => (enabledSet === null || enabledSet.has(c.class)) && !rejectSet.has(c.class.toLowerCase());
|
|
2580
2641
|
const minConfidence = typeof childStep.settings?.["minConfidence"] === "number" ? childStep.settings["minConfidence"] : 0;
|
|
2581
2642
|
const winner = output.classifications[0];
|
|
2582
2643
|
if (winner && passesClass(winner) && winner.score >= minConfidence) parent.ownLabels.push({
|
|
@@ -5543,7 +5604,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
5543
5604
|
totalRawBytes: items.reduce((s, it) => s + it.raw.length, 0)
|
|
5544
5605
|
} });
|
|
5545
5606
|
const start = performance.now();
|
|
5546
|
-
const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId);
|
|
5607
|
+
const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId, input.frameId ?? 0);
|
|
5547
5608
|
const totalMs = performance.now() - start;
|
|
5548
5609
|
this.log.info("runPipelineBatch fast path returned", { meta: {
|
|
5549
5610
|
phase: "batch",
|
|
@@ -7207,6 +7207,17 @@ var ModelCatalogEntrySchema = object({
|
|
|
7207
7207
|
"imagenet",
|
|
7208
7208
|
"none"
|
|
7209
7209
|
]).optional(),
|
|
7210
|
+
/**
|
|
7211
|
+
* The model already applies softmax IN-GRAPH — its raw output is a
|
|
7212
|
+
* probability distribution, not logits. When set, the `softmax`
|
|
7213
|
+
* postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
|
|
7214
|
+
* probability vector collapses it toward uniform (top-1 score craters far
|
|
7215
|
+
* below its true value, making every confidence gate meaningless). Absent ⇒
|
|
7216
|
+
* the output is raw logits and the postprocessor applies softmax (the normal
|
|
7217
|
+
* case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
|
|
7218
|
+
* TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
|
|
7219
|
+
*/
|
|
7220
|
+
outputProbabilities: boolean().optional(),
|
|
7210
7221
|
preprocessMode: _enum(["letterbox", "resize"]).optional(),
|
|
7211
7222
|
/**
|
|
7212
7223
|
* Per-MODEL postprocessor override. Absent ⇒ the step's own
|
|
@@ -12081,7 +12092,14 @@ var pipelineExecutorCapability = {
|
|
|
12081
12092
|
* (inputClasses ≠ null) are skipped and served per-track via
|
|
12082
12093
|
* pipelineRunner.runDetailSubtree (two-plane design).
|
|
12083
12094
|
*/
|
|
12084
|
-
plane: _enum(["full", "frame"]).optional()
|
|
12095
|
+
plane: _enum(["full", "frame"]).optional(),
|
|
12096
|
+
/**
|
|
12097
|
+
* Inference-device selector (Phase 2 multi-device). Format
|
|
12098
|
+
* `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
|
|
12099
|
+
* Omitted ⇒ the runner's default device (current single-engine
|
|
12100
|
+
* behaviour). Selects WHICH device pool of the node runs the call.
|
|
12101
|
+
*/
|
|
12102
|
+
deviceKey: string().optional()
|
|
12085
12103
|
}), PipelineRunResultBridge, { kind: "mutation" }),
|
|
12086
12104
|
/**
|
|
12087
12105
|
* Batched run — N raw frames packed into one cap call. The provider
|
|
@@ -12099,7 +12117,20 @@ var pipelineExecutorCapability = {
|
|
|
12099
12117
|
steps: array(PipelineStepInputSchema).min(1),
|
|
12100
12118
|
frames: array(FrameInputSchema).min(1).max(255),
|
|
12101
12119
|
deviceId: number().optional(),
|
|
12102
|
-
sessionId: string().optional()
|
|
12120
|
+
sessionId: string().optional(),
|
|
12121
|
+
/**
|
|
12122
|
+
* Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
|
|
12123
|
+
* the batch to the Python pool's bench preprocess cache
|
|
12124
|
+
* (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
|
|
12125
|
+
* preprocessed ONCE and every later inference is a pure-inference cache
|
|
12126
|
+
* hit — the sustained-throughput run measures inference, not
|
|
12127
|
+
* decode+preprocess+infer. Omitted/0 for live frames (all different →
|
|
12128
|
+
* full preprocess every call, correct). Fresh per sustained run;
|
|
12129
|
+
* released via `uncacheFrame`.
|
|
12130
|
+
*/
|
|
12131
|
+
frameId: number().int().nonnegative().optional(),
|
|
12132
|
+
/** Inference-device selector (Phase 2 multi-device); see runPipeline. */
|
|
12133
|
+
deviceKey: string().optional()
|
|
12103
12134
|
}), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }),
|
|
12104
12135
|
/**
|
|
12105
12136
|
* Cache a raw frame inside the Python inference pool's memory.
|
|
@@ -12516,7 +12547,14 @@ var RunnerCameraConfigSchema = object({
|
|
|
12516
12547
|
* camera's detect node differs from its source-owner (P2d, gated by the
|
|
12517
12548
|
* `remoteSourcingNodes` rollout setting).
|
|
12518
12549
|
*/
|
|
12519
|
-
frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
|
|
12550
|
+
frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
|
|
12551
|
+
/**
|
|
12552
|
+
* Inference-device selector for this camera's sessions (Phase 2 multi-device).
|
|
12553
|
+
* Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
|
|
12554
|
+
* omitted ⇒ the runner's default device. The engine itself stays node-local —
|
|
12555
|
+
* this only selects WHICH device pool of that node runs the session.
|
|
12556
|
+
*/
|
|
12557
|
+
deviceKey: string().optional()
|
|
12520
12558
|
});
|
|
12521
12559
|
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
12522
12560
|
/**
|
|
@@ -14087,6 +14125,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
|
|
|
14087
14125
|
kind: "mutation",
|
|
14088
14126
|
auth: "admin"
|
|
14089
14127
|
});
|
|
14128
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
14129
|
+
new Set(Object.values(DeviceType));
|
|
14090
14130
|
/**
|
|
14091
14131
|
* Evaluate `rules` against `items`. Returns the items partitioned
|
|
14092
14132
|
* into `passed` (kept by the gate) and `excluded` (dropped). When
|
|
@@ -21000,17 +21040,28 @@ var PlatformScoreSchema = object({
|
|
|
21000
21040
|
format: _enum([
|
|
21001
21041
|
"onnx",
|
|
21002
21042
|
"coreml",
|
|
21003
|
-
"openvino"
|
|
21043
|
+
"openvino",
|
|
21044
|
+
"tflite"
|
|
21004
21045
|
]),
|
|
21005
21046
|
score: number(),
|
|
21006
21047
|
reason: string(),
|
|
21007
21048
|
available: boolean()
|
|
21008
21049
|
});
|
|
21050
|
+
var InferenceDeviceDescriptorSchema = object({
|
|
21051
|
+
key: string(),
|
|
21052
|
+
backend: string(),
|
|
21053
|
+
device: string(),
|
|
21054
|
+
format: ModelFormatSchema,
|
|
21055
|
+
runtime: literal("python"),
|
|
21056
|
+
score: number(),
|
|
21057
|
+
available: boolean()
|
|
21058
|
+
});
|
|
21009
21059
|
var PlatformCapabilitiesSchema = object({
|
|
21010
21060
|
hardware: HardwareInfoSchema,
|
|
21011
21061
|
scores: array(PlatformScoreSchema).readonly(),
|
|
21012
21062
|
bestScore: PlatformScoreSchema,
|
|
21013
|
-
pythonPath: string().nullable()
|
|
21063
|
+
pythonPath: string().nullable(),
|
|
21064
|
+
devices: array(InferenceDeviceDescriptorSchema).readonly()
|
|
21014
21065
|
});
|
|
21015
21066
|
var ModelRequirementSchema = object({
|
|
21016
21067
|
modelId: string(),
|