@eyepop.ai/eyepop 3.19.0 → 3.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/eyepop.index.d.mts +376 -4
- package/dist/eyepop.index.d.ts +376 -4
- package/dist/eyepop.index.js +433 -91
- package/dist/eyepop.index.js.map +1 -1
- package/dist/eyepop.index.mjs +423 -90
- package/dist/eyepop.index.mjs.map +1 -1
- package/dist/eyepop.min.js +1 -1
- package/package.json +3 -1
package/dist/eyepop.index.js
CHANGED
|
@@ -8677,6 +8677,7 @@ __export(index_exports, {
|
|
|
8677
8677
|
EvaluationStatus: () => EvaluationStatus,
|
|
8678
8678
|
ExportedBy: () => ExportedBy,
|
|
8679
8679
|
EyePop: () => EyePop,
|
|
8680
|
+
EyePopDataWebSocketError: () => EyePopDataWebSocketError,
|
|
8680
8681
|
EyepopLineDecoder: () => EyepopLineDecoder,
|
|
8681
8682
|
ForwardOperatorType: () => ForwardOperatorType,
|
|
8682
8683
|
InferenceType: () => InferenceType,
|
|
@@ -8692,8 +8693,10 @@ __export(index_exports, {
|
|
|
8692
8693
|
ModelTrainingStage: () => ModelTrainingStage,
|
|
8693
8694
|
ModelType: () => ModelType,
|
|
8694
8695
|
MotionModel: () => MotionModel,
|
|
8696
|
+
PointCloud: () => PointCloud,
|
|
8695
8697
|
PopComponentType: () => PopComponentType,
|
|
8696
8698
|
PredictionVersion: () => PredictionVersion,
|
|
8699
|
+
QUATERNION_TOLERANCE: () => QUATERNION_TOLERANCE,
|
|
8697
8700
|
Semaphore: () => Semaphore,
|
|
8698
8701
|
Stream: () => Stream,
|
|
8699
8702
|
TaskMode: () => TaskMode,
|
|
@@ -8712,13 +8715,19 @@ __export(index_exports, {
|
|
|
8712
8715
|
WorkflowPhase: () => WorkflowPhase,
|
|
8713
8716
|
accessTokenCredential: () => accessTokenCredential,
|
|
8714
8717
|
apiKeyCredential: () => apiKeyCredential,
|
|
8718
|
+
cloudOfDepth: () => cloudOfDepth,
|
|
8719
|
+
cloudOfObject: () => cloudOfObject,
|
|
8720
|
+
cloudsOfPrediction: () => cloudsOfPrediction,
|
|
8715
8721
|
decodeDepthMap: () => decodeDepthMap,
|
|
8722
|
+
decodePointCloud: () => decodePointCloud,
|
|
8716
8723
|
default: () => index_default,
|
|
8717
8724
|
encodeMultipartFormData: () => encodeMultipartFormData,
|
|
8718
8725
|
getBaseUrl: () => getBaseUrl,
|
|
8719
8726
|
randomMultipartBoundary: () => randomMultipartBoundary,
|
|
8720
8727
|
readableStreamFromString: () => readableStreamFromString,
|
|
8721
|
-
resolveAuth: () => resolveAuth
|
|
8728
|
+
resolveAuth: () => resolveAuth,
|
|
8729
|
+
validateCamera: () => validateCamera,
|
|
8730
|
+
validatePop: () => validatePop
|
|
8722
8731
|
});
|
|
8723
8732
|
module.exports = __toCommonJS(index_exports);
|
|
8724
8733
|
|
|
@@ -9297,6 +9306,67 @@ Content-Disposition: form-data; name="${part.name}"\r
|
|
|
9297
9306
|
});
|
|
9298
9307
|
}
|
|
9299
9308
|
|
|
9309
|
+
// camera.ts
|
|
9310
|
+
var QUATERNION_TOLERANCE = 1e-3;
|
|
9311
|
+
function isFinite_(value) {
|
|
9312
|
+
return value === void 0 || Number.isFinite(value);
|
|
9313
|
+
}
|
|
9314
|
+
function validateCamera(camera) {
|
|
9315
|
+
if (camera.intrinsics !== void 0 && camera.hfovDegrees !== void 0) {
|
|
9316
|
+
throw new Error("camera.intrinsics and camera.hfovDegrees are alternatives, supply one");
|
|
9317
|
+
}
|
|
9318
|
+
if (camera.intrinsics === void 0 && camera.hfovDegrees === void 0) {
|
|
9319
|
+
throw new Error("camera requires either camera.intrinsics or camera.hfovDegrees");
|
|
9320
|
+
}
|
|
9321
|
+
if (camera.hfovDegrees !== void 0) {
|
|
9322
|
+
if (!(camera.hfovDegrees > 0 && camera.hfovDegrees < 180)) {
|
|
9323
|
+
throw new Error("camera.hfovDegrees must be a horizontal field of view in (0, 180) degrees");
|
|
9324
|
+
}
|
|
9325
|
+
} else {
|
|
9326
|
+
const intrinsics = camera.intrinsics;
|
|
9327
|
+
for (const [name, focal] of [
|
|
9328
|
+
["fx", intrinsics.fx],
|
|
9329
|
+
["fy", intrinsics.fy]
|
|
9330
|
+
]) {
|
|
9331
|
+
if (!(focal > 0) || !Number.isFinite(focal)) {
|
|
9332
|
+
throw new Error(`camera.intrinsics.${name} must be a positive, finite focal length`);
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
for (const [name, principal, extent] of [
|
|
9336
|
+
["cx", intrinsics.cx, "width"],
|
|
9337
|
+
["cy", intrinsics.cy, "height"]
|
|
9338
|
+
]) {
|
|
9339
|
+
if (!(principal >= 0 && principal <= 1)) {
|
|
9340
|
+
throw new Error(`camera.intrinsics.${name} must be within [0, 1] of the frame ${extent}`);
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9343
|
+
}
|
|
9344
|
+
if (camera.distortion !== void 0) {
|
|
9345
|
+
for (const name of ["k1", "k2", "p1", "p2", "k3"]) {
|
|
9346
|
+
if (!isFinite_(camera.distortion[name])) {
|
|
9347
|
+
throw new Error(`camera.distortion.${name} must be a finite number`);
|
|
9348
|
+
}
|
|
9349
|
+
}
|
|
9350
|
+
}
|
|
9351
|
+
if (camera.extrinsics !== void 0) {
|
|
9352
|
+
const translation = camera.extrinsics.translation;
|
|
9353
|
+
if (translation !== void 0) {
|
|
9354
|
+
for (const axis of ["x", "y", "z"]) {
|
|
9355
|
+
if (!Number.isFinite(translation[axis])) {
|
|
9356
|
+
throw new Error(`camera.extrinsics.translation.${axis} must be a finite number`);
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
9359
|
+
}
|
|
9360
|
+
const rotation = camera.extrinsics.rotation;
|
|
9361
|
+
if (rotation !== void 0) {
|
|
9362
|
+
const norm = Math.sqrt(rotation.w ** 2 + rotation.x ** 2 + rotation.y ** 2 + rotation.z ** 2);
|
|
9363
|
+
if (!(Math.abs(norm - 1) <= QUATERNION_TOLERANCE)) {
|
|
9364
|
+
throw new Error("camera.extrinsics.rotation must be a unit quaternion");
|
|
9365
|
+
}
|
|
9366
|
+
}
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
|
|
9300
9370
|
// worker/worker_types.ts
|
|
9301
9371
|
var PredictionVersion = /* @__PURE__ */ ((PredictionVersion3) => {
|
|
9302
9372
|
PredictionVersion3[PredictionVersion3["V1"] = 1] = "V1";
|
|
@@ -9351,6 +9421,16 @@ var ContourType = /* @__PURE__ */ ((ContourType2) => {
|
|
|
9351
9421
|
ContourType2["RECTANGLE"] = "rectangle";
|
|
9352
9422
|
return ContourType2;
|
|
9353
9423
|
})(ContourType || {});
|
|
9424
|
+
function validatePop(pop) {
|
|
9425
|
+
if (pop.depthMap !== void 0) {
|
|
9426
|
+
if (pop.depthMap.ability === void 0 === (pop.depthMap.abilityUuid === void 0)) {
|
|
9427
|
+
throw new Error("depthMap requires exactly one of ability or abilityUuid");
|
|
9428
|
+
}
|
|
9429
|
+
}
|
|
9430
|
+
if (pop.defaults?.camera !== void 0) {
|
|
9431
|
+
validateCamera(pop.defaults.camera);
|
|
9432
|
+
}
|
|
9433
|
+
}
|
|
9354
9434
|
|
|
9355
9435
|
// worker/webrtc_whip.ts
|
|
9356
9436
|
var import_uuid2 = require("uuid");
|
|
@@ -9841,7 +9921,7 @@ var UploadJob = class extends AbstractJob {
|
|
|
9841
9921
|
}
|
|
9842
9922
|
}
|
|
9843
9923
|
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?${queryParams.toString()}`;
|
|
9844
|
-
if (this._params.componentParams || this._params.roi) {
|
|
9924
|
+
if (this._params.componentParams || this._params.roi || this._params.camera) {
|
|
9845
9925
|
const formData = new FormData();
|
|
9846
9926
|
if (this._params.componentParams) {
|
|
9847
9927
|
const blob = new Blob([JSON.stringify(this._params.componentParams)], { type: "application/json" });
|
|
@@ -9855,6 +9935,10 @@ var UploadJob = class extends AbstractJob {
|
|
|
9855
9935
|
const blob = new Blob([JSON.stringify(this._params.fps)], { type: "application/json" });
|
|
9856
9936
|
formData.append("fps", blob);
|
|
9857
9937
|
}
|
|
9938
|
+
if (this._params.camera) {
|
|
9939
|
+
const blob = new Blob([JSON.stringify(this._params.camera)], { type: "application/json" });
|
|
9940
|
+
formData.append("camera", blob);
|
|
9941
|
+
}
|
|
9858
9942
|
const fileBlob = await new Response(await this.uploadBody()).blob();
|
|
9859
9943
|
formData.append("file", fileBlob);
|
|
9860
9944
|
const headers = {
|
|
@@ -9936,7 +10020,7 @@ var UploadJob = class extends AbstractJob {
|
|
|
9936
10020
|
}
|
|
9937
10021
|
}
|
|
9938
10022
|
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?${queryParams.toString()}`;
|
|
9939
|
-
if (this._params.componentParams || this._params.roi) {
|
|
10023
|
+
if (this._params.componentParams || this._params.roi || this._params.camera) {
|
|
9940
10024
|
const formData = new FormData();
|
|
9941
10025
|
if (this._params.componentParams) {
|
|
9942
10026
|
const blob = new Blob([JSON.stringify(this._params.componentParams)], { type: "application/json" });
|
|
@@ -9950,6 +10034,10 @@ var UploadJob = class extends AbstractJob {
|
|
|
9950
10034
|
const blob = new Blob([JSON.stringify(this._params.fps)], { type: "application/json" });
|
|
9951
10035
|
formData.append("fps", blob);
|
|
9952
10036
|
}
|
|
10037
|
+
if (this._params.camera) {
|
|
10038
|
+
const blob = new Blob([JSON.stringify(this._params.camera)], { type: "application/json" });
|
|
10039
|
+
formData.append("camera", blob);
|
|
10040
|
+
}
|
|
9953
10041
|
const fileBlob = await new Response(await this.uploadBody()).blob();
|
|
9954
10042
|
formData.append("file", fileBlob);
|
|
9955
10043
|
const headers = {
|
|
@@ -10006,6 +10094,7 @@ var LoadFromJob = class extends AbstractJob {
|
|
|
10006
10094
|
params: this._params.componentParams,
|
|
10007
10095
|
roi: this._params.roi,
|
|
10008
10096
|
fps: this._params.fps,
|
|
10097
|
+
camera: this._params.camera,
|
|
10009
10098
|
version: this._version
|
|
10010
10099
|
};
|
|
10011
10100
|
if (this._params.motionDetect) {
|
|
@@ -10066,6 +10155,9 @@ var UploadGroupJob = class extends AbstractJob {
|
|
|
10066
10155
|
if (this._params.fps) {
|
|
10067
10156
|
parts.push({ name: "fps", contentType: "application/json", content: JSON.stringify(this._params.fps) });
|
|
10068
10157
|
}
|
|
10158
|
+
if (this._params.camera) {
|
|
10159
|
+
parts.push({ name: "camera", contentType: "application/json", content: JSON.stringify(this._params.camera) });
|
|
10160
|
+
}
|
|
10069
10161
|
for (const source of this._sources) {
|
|
10070
10162
|
parts.push({ name: "file", contentType: source.mimeType, content: source.stream });
|
|
10071
10163
|
}
|
|
@@ -10113,6 +10205,9 @@ var LoadFromGroupJob = class extends AbstractJob {
|
|
|
10113
10205
|
if (this._params.roi) {
|
|
10114
10206
|
body["roi"] = this._params.roi;
|
|
10115
10207
|
}
|
|
10208
|
+
if (this._params.camera) {
|
|
10209
|
+
body["camera"] = this._params.camera;
|
|
10210
|
+
}
|
|
10116
10211
|
if (this._params.motionDetect) {
|
|
10117
10212
|
Object.assign(body, this._params.motionDetect);
|
|
10118
10213
|
}
|
|
@@ -10151,6 +10246,7 @@ var LoadFromAssetUuidJob = class extends AbstractJob {
|
|
|
10151
10246
|
params: this._params.componentParams,
|
|
10152
10247
|
roi: this._params.roi,
|
|
10153
10248
|
fps: this._params.fps,
|
|
10249
|
+
camera: this._params.camera,
|
|
10154
10250
|
version: this._version
|
|
10155
10251
|
};
|
|
10156
10252
|
if (this._params.motionDetect) {
|
|
@@ -10205,6 +10301,7 @@ var LoadMediaStreamJob = class extends AbstractJob {
|
|
|
10205
10301
|
params: this._params.componentParams,
|
|
10206
10302
|
roi: this._params.roi,
|
|
10207
10303
|
fps: this._params.fps,
|
|
10304
|
+
camera: this._params.camera,
|
|
10208
10305
|
version: this._version
|
|
10209
10306
|
};
|
|
10210
10307
|
if (this._params.motionDetect) {
|
|
@@ -10816,6 +10913,7 @@ var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
|
10816
10913
|
return this.options().pop || null;
|
|
10817
10914
|
}
|
|
10818
10915
|
async changePop(pop) {
|
|
10916
|
+
validatePop(pop);
|
|
10819
10917
|
if (this.options().popId == "transient" /* Transient */) {
|
|
10820
10918
|
await this.changeTransientPop(pop);
|
|
10821
10919
|
return;
|
|
@@ -10888,7 +10986,22 @@ var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
|
10888
10986
|
return Promise.reject("unknown source type");
|
|
10889
10987
|
}
|
|
10890
10988
|
}
|
|
10989
|
+
/**
|
|
10990
|
+
* Reject a source's calibration before any work is started for it.
|
|
10991
|
+
*
|
|
10992
|
+
* Called by every entry point that takes ProcessParams rather than at the
|
|
10993
|
+
* one boundary they share, because they have none: the group methods build
|
|
10994
|
+
* their jobs directly instead of going through processV2. It runs before
|
|
10995
|
+
* the concurrency limit is acquired, so a request that can never be sent
|
|
10996
|
+
* does not hold a slot.
|
|
10997
|
+
*/
|
|
10998
|
+
validateProcessParams(params) {
|
|
10999
|
+
if (params.camera !== void 0) {
|
|
11000
|
+
validateCamera(params.camera);
|
|
11001
|
+
}
|
|
11002
|
+
}
|
|
10891
11003
|
async processV2(request) {
|
|
11004
|
+
this.validateProcessParams(request);
|
|
10892
11005
|
if (request.source.file !== void 0) {
|
|
10893
11006
|
return this.uploadFile(request.source, request);
|
|
10894
11007
|
} else if (request.source.stream !== void 0) {
|
|
@@ -10909,6 +11022,7 @@ var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
|
10909
11022
|
if (paths.length === 0) {
|
|
10910
11023
|
throw new Error("upload group requires at least one path");
|
|
10911
11024
|
}
|
|
11025
|
+
this.validateProcessParams(params);
|
|
10912
11026
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10913
11027
|
throw new Error("endpoint not connected, use connect()");
|
|
10914
11028
|
}
|
|
@@ -10947,6 +11061,7 @@ var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
|
10947
11061
|
if (mimeTypes !== void 0 && mimeTypes.length !== streams.length) {
|
|
10948
11062
|
throw new Error("mimeTypes must have the same length as streams");
|
|
10949
11063
|
}
|
|
11064
|
+
this.validateProcessParams(params);
|
|
10950
11065
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10951
11066
|
throw new Error("endpoint not connected, use connect()");
|
|
10952
11067
|
}
|
|
@@ -10975,6 +11090,7 @@ var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
|
10975
11090
|
if (urls.length === 0) {
|
|
10976
11091
|
throw new Error("load from group requires at least one url");
|
|
10977
11092
|
}
|
|
11093
|
+
this.validateProcessParams(params);
|
|
10978
11094
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
10979
11095
|
throw new Error("endpoint not connected, use connect()");
|
|
10980
11096
|
}
|
|
@@ -11522,57 +11638,8 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
11522
11638
|
};
|
|
11523
11639
|
}
|
|
11524
11640
|
|
|
11525
|
-
//
|
|
11526
|
-
|
|
11527
|
-
var resultArray = [];
|
|
11528
|
-
if (strArray.length === 0) {
|
|
11529
|
-
return "";
|
|
11530
|
-
}
|
|
11531
|
-
if (typeof strArray[0] !== "string") {
|
|
11532
|
-
throw new TypeError("Url must be a string. Received " + strArray[0]);
|
|
11533
|
-
}
|
|
11534
|
-
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
|
|
11535
|
-
var first = strArray.shift();
|
|
11536
|
-
strArray[0] = first + strArray[0];
|
|
11537
|
-
}
|
|
11538
|
-
if (strArray[0].match(/^file:\/\/\//)) {
|
|
11539
|
-
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
|
|
11540
|
-
} else {
|
|
11541
|
-
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
|
|
11542
|
-
}
|
|
11543
|
-
for (var i = 0; i < strArray.length; i++) {
|
|
11544
|
-
var component = strArray[i];
|
|
11545
|
-
if (typeof component !== "string") {
|
|
11546
|
-
throw new TypeError("Url must be a string. Received " + component);
|
|
11547
|
-
}
|
|
11548
|
-
if (component === "") {
|
|
11549
|
-
continue;
|
|
11550
|
-
}
|
|
11551
|
-
if (i > 0) {
|
|
11552
|
-
component = component.replace(/^[\/]+/, "");
|
|
11553
|
-
}
|
|
11554
|
-
if (i < strArray.length - 1) {
|
|
11555
|
-
component = component.replace(/[\/]+$/, "");
|
|
11556
|
-
} else {
|
|
11557
|
-
component = component.replace(/[\/]+$/, "/");
|
|
11558
|
-
}
|
|
11559
|
-
resultArray.push(component);
|
|
11560
|
-
}
|
|
11561
|
-
var str = resultArray.join("/");
|
|
11562
|
-
str = str.replace(/\/(\?|&|#[^!])/g, "$1");
|
|
11563
|
-
var parts = str.split("?");
|
|
11564
|
-
str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
|
|
11565
|
-
return str;
|
|
11566
|
-
}
|
|
11567
|
-
function urlJoin() {
|
|
11568
|
-
var input;
|
|
11569
|
-
if (typeof arguments[0] === "object") {
|
|
11570
|
-
input = arguments[0];
|
|
11571
|
-
} else {
|
|
11572
|
-
input = [].slice.call(arguments);
|
|
11573
|
-
}
|
|
11574
|
-
return normalize(input);
|
|
11575
|
-
}
|
|
11641
|
+
// data/data_endpoint.ts
|
|
11642
|
+
var import_url_join = __toESM(require("url-join"));
|
|
11576
11643
|
|
|
11577
11644
|
// data/data_types.ts
|
|
11578
11645
|
var DataApiType = /* @__PURE__ */ ((DataApiType2) => {
|
|
@@ -11925,6 +11992,33 @@ var EvaluateDatasetJob = class {
|
|
|
11925
11992
|
// data/data_endpoint.ts
|
|
11926
11993
|
var WS_INITIAL_RECONNECT_DELAY = 1e3;
|
|
11927
11994
|
var WS_MAX_RECONNECT_DELAY = 6e4;
|
|
11995
|
+
function ws_origin(url) {
|
|
11996
|
+
try {
|
|
11997
|
+
return new URL(url).origin;
|
|
11998
|
+
} catch {
|
|
11999
|
+
return url;
|
|
12000
|
+
}
|
|
12001
|
+
}
|
|
12002
|
+
function ws_failure_reason(event, sourceError) {
|
|
12003
|
+
if (sourceError instanceof Error) {
|
|
12004
|
+
return sourceError.message;
|
|
12005
|
+
}
|
|
12006
|
+
if (typeof sourceError === "string") {
|
|
12007
|
+
return sourceError;
|
|
12008
|
+
}
|
|
12009
|
+
return event?.message ?? "";
|
|
12010
|
+
}
|
|
12011
|
+
var EyePopDataWebSocketError = class extends Error {
|
|
12012
|
+
constructor(url, event) {
|
|
12013
|
+
const sourceError = event?.error ?? event;
|
|
12014
|
+
const reason = ws_failure_reason(event, sourceError);
|
|
12015
|
+
super(reason ? `EyePop Dataset event WebSocket connection failed: ${reason}` : "EyePop Dataset event WebSocket connection failed");
|
|
12016
|
+
this.code = "DATA_WEBSOCKET_CONNECTION_FAILED";
|
|
12017
|
+
this.name = "EyePopDataWebSocketError";
|
|
12018
|
+
this.endpoint = ws_origin(url);
|
|
12019
|
+
this.sourceError = sourceError;
|
|
12020
|
+
}
|
|
12021
|
+
};
|
|
11928
12022
|
function omit_nulls(_, value) {
|
|
11929
12023
|
if (value === null) {
|
|
11930
12024
|
return void 0;
|
|
@@ -11938,6 +12032,9 @@ var DataEndpoint = class extends Endpoint {
|
|
|
11938
12032
|
this.vlmApiUrl = null;
|
|
11939
12033
|
this._ws = null;
|
|
11940
12034
|
this._ws_current_reconnect_delay = null;
|
|
12035
|
+
this._ws_reconnect_timeout = null;
|
|
12036
|
+
this._ws_reconnect_enabled = false;
|
|
12037
|
+
this._ws_connecting = null;
|
|
11941
12038
|
this._accountId = options.accountId || null;
|
|
11942
12039
|
this._account_event_handlers = [];
|
|
11943
12040
|
this._dataset_uuid_to_event_handlers = /* @__PURE__ */ new Map();
|
|
@@ -11961,14 +12058,15 @@ var DataEndpoint = class extends Endpoint {
|
|
|
11961
12058
|
};
|
|
11962
12059
|
}
|
|
11963
12060
|
async disconnect(wait = true) {
|
|
12061
|
+
this._ws_reconnect_enabled = false;
|
|
12062
|
+
if (this._ws_reconnect_timeout) {
|
|
12063
|
+
clearTimeout(this._ws_reconnect_timeout);
|
|
12064
|
+
this._ws_reconnect_timeout = null;
|
|
12065
|
+
}
|
|
11964
12066
|
this.datasetApiUrl = null;
|
|
11965
12067
|
this.vlmApiUrl = null;
|
|
11966
12068
|
if (this._ws) {
|
|
11967
|
-
|
|
11968
|
-
this._ws.close();
|
|
11969
|
-
} catch (e) {
|
|
11970
|
-
this._logger.warn("ignored exception", e);
|
|
11971
|
-
}
|
|
12069
|
+
this.close_ws(this._ws, "unsubscribe");
|
|
11972
12070
|
this._ws = null;
|
|
11973
12071
|
}
|
|
11974
12072
|
await super.disconnect(wait);
|
|
@@ -12006,13 +12104,14 @@ var DataEndpoint = class extends Endpoint {
|
|
|
12006
12104
|
const vlmApiUrl = new URL(config.vlm_api_url, this.eyepopUrl());
|
|
12007
12105
|
this.vlmApiUrl = vlmApiUrl.toString();
|
|
12008
12106
|
if (this.options().disableWs) {
|
|
12107
|
+
this._ws_reconnect_enabled = false;
|
|
12009
12108
|
this._logger.info("disabled ws connection");
|
|
12010
12109
|
} else {
|
|
12011
12110
|
await this.reconnect_ws();
|
|
12012
12111
|
}
|
|
12013
12112
|
if (this.options().useCookie) {
|
|
12014
12113
|
const client = this._client;
|
|
12015
|
-
const url =
|
|
12114
|
+
const url = (0, import_url_join.default)(this.datasetApiUrl, "security", "check?set_cookie=true");
|
|
12016
12115
|
const headers2 = {
|
|
12017
12116
|
Authorization: await this.authorizationHeader()
|
|
12018
12117
|
};
|
|
@@ -12029,37 +12128,68 @@ var DataEndpoint = class extends Endpoint {
|
|
|
12029
12128
|
return Promise.resolve(this);
|
|
12030
12129
|
}
|
|
12031
12130
|
async reconnect_ws() {
|
|
12131
|
+
if (this._ws_connecting) {
|
|
12132
|
+
return this._ws_connecting;
|
|
12133
|
+
}
|
|
12134
|
+
const connecting = this.open_ws();
|
|
12135
|
+
this._ws_connecting = connecting;
|
|
12136
|
+
try {
|
|
12137
|
+
await connecting;
|
|
12138
|
+
} finally {
|
|
12139
|
+
this._ws_connecting = null;
|
|
12140
|
+
}
|
|
12141
|
+
}
|
|
12142
|
+
async open_ws() {
|
|
12032
12143
|
if (this._ws) {
|
|
12033
|
-
this._ws
|
|
12144
|
+
this.close_ws(this._ws, "unsubscribe");
|
|
12034
12145
|
this._ws = null;
|
|
12035
12146
|
}
|
|
12036
12147
|
const baseUrl = this.datasetApiUrl?.replace("https://", "wss://").replace("http://", "ws://");
|
|
12037
12148
|
if (!baseUrl) {
|
|
12038
12149
|
return;
|
|
12039
12150
|
}
|
|
12040
|
-
const ws_url =
|
|
12151
|
+
const ws_url = (0, import_url_join.default)(baseUrl, "events");
|
|
12041
12152
|
this._requestLogger.debug("about to connect ws to: %s", ws_url);
|
|
12042
12153
|
return new Promise((resolve, reject) => {
|
|
12154
|
+
let settled = false;
|
|
12155
|
+
const settle_ok = () => {
|
|
12156
|
+
settled = true;
|
|
12157
|
+
resolve();
|
|
12158
|
+
};
|
|
12159
|
+
const settle_err = (error) => {
|
|
12160
|
+
settled = true;
|
|
12161
|
+
reject(error);
|
|
12162
|
+
};
|
|
12043
12163
|
const ws = createWebSocket(ws_url);
|
|
12044
12164
|
if (!ws) {
|
|
12045
|
-
return
|
|
12165
|
+
return settle_ok();
|
|
12046
12166
|
}
|
|
12047
12167
|
this._ws = ws;
|
|
12048
|
-
ws.onopen =
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
ws
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12168
|
+
ws.onopen = () => {
|
|
12169
|
+
void this.authorizationHeader().then((auth_header) => {
|
|
12170
|
+
if (this._ws !== ws) {
|
|
12171
|
+
this.close_ws(ws, "unsubscribe");
|
|
12172
|
+
settle_ok();
|
|
12173
|
+
return;
|
|
12174
|
+
}
|
|
12175
|
+
let msg = JSON.stringify({ authorization: auth_header });
|
|
12176
|
+
this._requestLogger.debug("ws send: %s", msg);
|
|
12177
|
+
ws.send(msg);
|
|
12178
|
+
msg = JSON.stringify({ subscribe: { account_uuid: this._accountId } });
|
|
12179
|
+
this._requestLogger.debug("ws send: %s", msg);
|
|
12180
|
+
ws.send(msg);
|
|
12181
|
+
for (const dataset_uuid of this._dataset_uuid_to_event_handlers.keys()) {
|
|
12182
|
+
const msg2 = JSON.stringify({ subscribe: { dataset_uuid } });
|
|
12183
|
+
this._requestLogger.debug("ws send: %s", msg2);
|
|
12184
|
+
ws.send(msg2);
|
|
12185
|
+
}
|
|
12186
|
+
this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
|
|
12187
|
+
this._ws_reconnect_enabled = true;
|
|
12188
|
+
settle_ok();
|
|
12189
|
+
}).catch((error) => {
|
|
12190
|
+
this.close_ws(ws, "authorization failed", 1011);
|
|
12191
|
+
settle_err(error);
|
|
12192
|
+
});
|
|
12063
12193
|
};
|
|
12064
12194
|
ws.onmessage = (event) => {
|
|
12065
12195
|
const data = JSON.parse(event.data);
|
|
@@ -12070,24 +12200,54 @@ var DataEndpoint = class extends Endpoint {
|
|
|
12070
12200
|
ws.onclose = (event) => {
|
|
12071
12201
|
const { code, reason } = event;
|
|
12072
12202
|
this._requestLogger.debug("ws closed: %d %s", code, reason);
|
|
12073
|
-
if (
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
}
|
|
12079
|
-
setTimeout(async () => {
|
|
12080
|
-
await this.reconnect_ws();
|
|
12081
|
-
}, this._ws_current_reconnect_delay);
|
|
12203
|
+
if (!settled) {
|
|
12204
|
+
settle_err(new EyePopDataWebSocketError(ws_url, new Error(`closed before the connection was established: ${code} ${reason}`)));
|
|
12205
|
+
}
|
|
12206
|
+
if (this._ws !== ws) {
|
|
12207
|
+
return;
|
|
12082
12208
|
}
|
|
12209
|
+
this._ws = null;
|
|
12210
|
+
this.schedule_ws_reconnect();
|
|
12083
12211
|
};
|
|
12084
12212
|
ws.onerror = (event) => {
|
|
12085
|
-
|
|
12086
|
-
|
|
12213
|
+
const error = new EyePopDataWebSocketError(ws_url, event);
|
|
12214
|
+
this._logger.error({ err: error }, "dataset event WebSocket connection failed");
|
|
12215
|
+
settle_err(error);
|
|
12087
12216
|
return null;
|
|
12088
12217
|
};
|
|
12089
12218
|
});
|
|
12090
12219
|
}
|
|
12220
|
+
close_ws(ws, reason, code = 1e3) {
|
|
12221
|
+
try {
|
|
12222
|
+
ws.close(code, reason);
|
|
12223
|
+
} catch (e) {
|
|
12224
|
+
this._logger.warn({ err: e }, "ignored exception closing the dataset event WebSocket");
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12227
|
+
schedule_ws_reconnect() {
|
|
12228
|
+
if (!this._ws_reconnect_enabled || this._ws_reconnect_timeout) {
|
|
12229
|
+
return;
|
|
12230
|
+
}
|
|
12231
|
+
if (!this._ws_current_reconnect_delay) {
|
|
12232
|
+
this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
|
|
12233
|
+
} else if (this._ws_current_reconnect_delay < WS_MAX_RECONNECT_DELAY) {
|
|
12234
|
+
this._ws_current_reconnect_delay *= 1.5;
|
|
12235
|
+
}
|
|
12236
|
+
this._ws_reconnect_timeout = setTimeout(() => {
|
|
12237
|
+
if (!this._ws_reconnect_enabled) {
|
|
12238
|
+
this._ws_reconnect_timeout = null;
|
|
12239
|
+
return;
|
|
12240
|
+
}
|
|
12241
|
+
void this.reconnect_ws().catch((error) => {
|
|
12242
|
+
this._requestLogger.debug("dataset event WebSocket reconnect failed: %s", error);
|
|
12243
|
+
}).finally(() => {
|
|
12244
|
+
this._ws_reconnect_timeout = null;
|
|
12245
|
+
if (!this._ws) {
|
|
12246
|
+
this.schedule_ws_reconnect();
|
|
12247
|
+
}
|
|
12248
|
+
});
|
|
12249
|
+
}, this._ws_current_reconnect_delay);
|
|
12250
|
+
}
|
|
12091
12251
|
options() {
|
|
12092
12252
|
return this._options;
|
|
12093
12253
|
}
|
|
@@ -12112,7 +12272,7 @@ var DataEndpoint = class extends Endpoint {
|
|
|
12112
12272
|
body: options.body
|
|
12113
12273
|
};
|
|
12114
12274
|
this._requestLogger.debug("Request - " + ri.method + " " + path2 + " BODY: " + (ri.body ? ri.body : ""));
|
|
12115
|
-
return await client.fetch(
|
|
12275
|
+
return await client.fetch((0, import_url_join.default)(baseUrl ?? "", path2), ri);
|
|
12116
12276
|
});
|
|
12117
12277
|
if (response.status === 204) {
|
|
12118
12278
|
return null;
|
|
@@ -12850,6 +13010,176 @@ function decodeDepthMap(depth) {
|
|
|
12850
13010
|
return new DepthMap(depth.width, depth.height, values);
|
|
12851
13011
|
}
|
|
12852
13012
|
|
|
13013
|
+
// point_cloud.ts
|
|
13014
|
+
var VALUES_PER_POINT = 3;
|
|
13015
|
+
var isLittleEndianPlatform2 = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
|
|
13016
|
+
function base64ToBytes2(base64) {
|
|
13017
|
+
if (typeof Buffer !== "undefined") {
|
|
13018
|
+
const buffer = Buffer.from(base64, "base64");
|
|
13019
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
13020
|
+
}
|
|
13021
|
+
const binary = atob(base64);
|
|
13022
|
+
const bytes = new Uint8Array(binary.length);
|
|
13023
|
+
for (let i = 0; i < binary.length; i++) {
|
|
13024
|
+
bytes[i] = binary.charCodeAt(i);
|
|
13025
|
+
}
|
|
13026
|
+
return bytes;
|
|
13027
|
+
}
|
|
13028
|
+
var PointCloud = class {
|
|
13029
|
+
constructor(width, height, points, box) {
|
|
13030
|
+
this.width = width;
|
|
13031
|
+
this.height = height;
|
|
13032
|
+
this.points = points;
|
|
13033
|
+
this.box = box;
|
|
13034
|
+
}
|
|
13035
|
+
/**
|
|
13036
|
+
* The world point for pixel (i, j), or undefined where the worker placed none.
|
|
13037
|
+
*
|
|
13038
|
+
* (i, j) indexes the cloud's own grid - the mask bitmap, or the depth map
|
|
13039
|
+
* for a scene cloud: i is the column, j is the row.
|
|
13040
|
+
*/
|
|
13041
|
+
at(i, j) {
|
|
13042
|
+
if (!(i >= 0 && i < this.width && j >= 0 && j < this.height)) {
|
|
13043
|
+
throw new Error(`(${i}, ${j}) is outside a ${this.width}x${this.height} cloud`);
|
|
13044
|
+
}
|
|
13045
|
+
const offset = (j * this.width + i) * VALUES_PER_POINT;
|
|
13046
|
+
const x = this.points[offset];
|
|
13047
|
+
const y = this.points[offset + 1];
|
|
13048
|
+
const z = this.points[offset + 2];
|
|
13049
|
+
if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) {
|
|
13050
|
+
return void 0;
|
|
13051
|
+
}
|
|
13052
|
+
return { x, y, z };
|
|
13053
|
+
}
|
|
13054
|
+
/**
|
|
13055
|
+
* The world point for a source frame coordinate inside the cloud's box.
|
|
13056
|
+
*
|
|
13057
|
+
* Needs a cloud built with cloudOfObject(), or with cloudOfDepth() and the
|
|
13058
|
+
* frame size: the grid covers a box, and nothing else knows where it sits.
|
|
13059
|
+
*/
|
|
13060
|
+
atSource(x, y) {
|
|
13061
|
+
if (this.box === void 0) {
|
|
13062
|
+
throw new Error("atSource needs a box; build with cloudOfObject or cloudOfDepth");
|
|
13063
|
+
}
|
|
13064
|
+
if (!(this.box.width > 0) || !(this.box.height > 0)) {
|
|
13065
|
+
throw new Error(`invalid bounding box extent: ${this.box.width}x${this.box.height}`);
|
|
13066
|
+
}
|
|
13067
|
+
const i = Math.min(Math.max(Math.floor((x - this.box.x) / this.box.width * this.width), 0), this.width - 1);
|
|
13068
|
+
const j = Math.min(Math.max(Math.floor((y - this.box.y) / this.box.height * this.height), 0), this.height - 1);
|
|
13069
|
+
return this.at(i, j);
|
|
13070
|
+
}
|
|
13071
|
+
isPlaced(i, j) {
|
|
13072
|
+
return this.at(i, j) !== void 0;
|
|
13073
|
+
}
|
|
13074
|
+
/**
|
|
13075
|
+
* Just the points the worker placed.
|
|
13076
|
+
*
|
|
13077
|
+
* The shape a scatter plot or an export wants: the grid with its NaN holes
|
|
13078
|
+
* dropped, and no mask to apply first.
|
|
13079
|
+
*/
|
|
13080
|
+
get placedPoints() {
|
|
13081
|
+
const placed = [];
|
|
13082
|
+
for (let offset = 0; offset < this.points.length; offset += VALUES_PER_POINT) {
|
|
13083
|
+
const x = this.points[offset];
|
|
13084
|
+
const y = this.points[offset + 1];
|
|
13085
|
+
const z = this.points[offset + 2];
|
|
13086
|
+
if (!Number.isNaN(x) && !Number.isNaN(y) && !Number.isNaN(z)) {
|
|
13087
|
+
placed.push({ x, y, z });
|
|
13088
|
+
}
|
|
13089
|
+
}
|
|
13090
|
+
return placed;
|
|
13091
|
+
}
|
|
13092
|
+
/**
|
|
13093
|
+
* Per axis (min, max) in metres over the placed points, or undefined if none were.
|
|
13094
|
+
*
|
|
13095
|
+
* The counterpart to DepthMap's finiteMin/finiteMax, which are one axis
|
|
13096
|
+
* because a depth map has one value per pixel.
|
|
13097
|
+
*/
|
|
13098
|
+
get bounds() {
|
|
13099
|
+
let found = false;
|
|
13100
|
+
const min = { x: Number.POSITIVE_INFINITY, y: Number.POSITIVE_INFINITY, z: Number.POSITIVE_INFINITY };
|
|
13101
|
+
const max = { x: Number.NEGATIVE_INFINITY, y: Number.NEGATIVE_INFINITY, z: Number.NEGATIVE_INFINITY };
|
|
13102
|
+
for (let offset = 0; offset < this.points.length; offset += VALUES_PER_POINT) {
|
|
13103
|
+
const x = this.points[offset];
|
|
13104
|
+
const y = this.points[offset + 1];
|
|
13105
|
+
const z = this.points[offset + 2];
|
|
13106
|
+
if (Number.isNaN(x) || Number.isNaN(y) || Number.isNaN(z)) {
|
|
13107
|
+
continue;
|
|
13108
|
+
}
|
|
13109
|
+
found = true;
|
|
13110
|
+
min.x = Math.min(min.x, x);
|
|
13111
|
+
min.y = Math.min(min.y, y);
|
|
13112
|
+
min.z = Math.min(min.z, z);
|
|
13113
|
+
max.x = Math.max(max.x, x);
|
|
13114
|
+
max.y = Math.max(max.y, y);
|
|
13115
|
+
max.z = Math.max(max.z, z);
|
|
13116
|
+
}
|
|
13117
|
+
return found ? { min, max } : void 0;
|
|
13118
|
+
}
|
|
13119
|
+
};
|
|
13120
|
+
function decode(width, height, world, box) {
|
|
13121
|
+
if (!Number.isSafeInteger(width) || width <= 0 || !Number.isSafeInteger(height) || height <= 0) {
|
|
13122
|
+
throw new Error(`invalid point cloud dimensions: ${width}x${height}`);
|
|
13123
|
+
}
|
|
13124
|
+
const bytes = base64ToBytes2(world);
|
|
13125
|
+
const count = width * height * VALUES_PER_POINT;
|
|
13126
|
+
if (bytes.byteLength !== count * 4) {
|
|
13127
|
+
throw new Error(`'world' holds ${bytes.byteLength} bytes, expected ${count * 4} for ${width}x${height} xyz float32`);
|
|
13128
|
+
}
|
|
13129
|
+
let points;
|
|
13130
|
+
if (isLittleEndianPlatform2) {
|
|
13131
|
+
const aligned = new Uint8Array(bytes);
|
|
13132
|
+
points = new Float32Array(aligned.buffer, 0, count);
|
|
13133
|
+
} else {
|
|
13134
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13135
|
+
points = new Float32Array(count);
|
|
13136
|
+
for (let i = 0; i < count; i++) {
|
|
13137
|
+
points[i] = view.getFloat32(i * 4, true);
|
|
13138
|
+
}
|
|
13139
|
+
}
|
|
13140
|
+
return new PointCloud(width, height, points, box);
|
|
13141
|
+
}
|
|
13142
|
+
function decodePointCloud(mask, box) {
|
|
13143
|
+
if (mask === void 0 || mask.world === void 0) {
|
|
13144
|
+
return void 0;
|
|
13145
|
+
}
|
|
13146
|
+
return decode(mask.width, mask.height, mask.world, box);
|
|
13147
|
+
}
|
|
13148
|
+
function cloudOfObject(obj) {
|
|
13149
|
+
if (obj === void 0 || obj.mask === void 0) {
|
|
13150
|
+
return void 0;
|
|
13151
|
+
}
|
|
13152
|
+
return decodePointCloud(obj.mask, { x: obj.x, y: obj.y, width: obj.width, height: obj.height });
|
|
13153
|
+
}
|
|
13154
|
+
function cloudOfDepth(depth, sourceWidth, sourceHeight) {
|
|
13155
|
+
if (depth === void 0 || depth.world === void 0) {
|
|
13156
|
+
return void 0;
|
|
13157
|
+
}
|
|
13158
|
+
const box = sourceWidth && sourceHeight ? { x: 0, y: 0, width: sourceWidth, height: sourceHeight } : void 0;
|
|
13159
|
+
return decode(depth.width, depth.height, depth.world, box);
|
|
13160
|
+
}
|
|
13161
|
+
function cloudsOfPrediction(prediction) {
|
|
13162
|
+
const clouds = [];
|
|
13163
|
+
if (prediction === void 0) {
|
|
13164
|
+
return clouds;
|
|
13165
|
+
}
|
|
13166
|
+
const walk = (objects) => {
|
|
13167
|
+
for (const obj of objects ?? []) {
|
|
13168
|
+
const cloud = cloudOfObject(obj);
|
|
13169
|
+
if (cloud !== void 0) {
|
|
13170
|
+
clouds.push(cloud);
|
|
13171
|
+
}
|
|
13172
|
+
walk(obj.objects);
|
|
13173
|
+
}
|
|
13174
|
+
};
|
|
13175
|
+
walk(prediction.objects);
|
|
13176
|
+
const scene = cloudOfDepth(prediction.depth, prediction.source_width, prediction.source_height);
|
|
13177
|
+
if (scene !== void 0) {
|
|
13178
|
+
clouds.push(scene);
|
|
13179
|
+
}
|
|
13180
|
+
return clouds;
|
|
13181
|
+
}
|
|
13182
|
+
|
|
12853
13183
|
// worker/webrtc_whep.ts
|
|
12854
13184
|
var WebrtcWhep = class extends WebrtcBase {
|
|
12855
13185
|
constructor(ingressId, getSession, client, requestLogger) {
|
|
@@ -12954,6 +13284,9 @@ var EyePop;
|
|
|
12954
13284
|
} : void 0;
|
|
12955
13285
|
EyePop2.endpoint = workerEndpoint;
|
|
12956
13286
|
function workerEndpoint(opts = {}) {
|
|
13287
|
+
if (opts.pop !== void 0) {
|
|
13288
|
+
validatePop(opts.pop);
|
|
13289
|
+
}
|
|
12957
13290
|
if (opts.isLocalMode === void 0) {
|
|
12958
13291
|
opts.isLocalMode = stringToBooleanSafe(readEnv("EYEPOP_LOCAL_MODE"));
|
|
12959
13292
|
}
|
|
@@ -13090,6 +13423,7 @@ var index_default = EyePop;
|
|
|
13090
13423
|
EvaluationStatus,
|
|
13091
13424
|
ExportedBy,
|
|
13092
13425
|
EyePop,
|
|
13426
|
+
EyePopDataWebSocketError,
|
|
13093
13427
|
EyepopLineDecoder,
|
|
13094
13428
|
ForwardOperatorType,
|
|
13095
13429
|
InferenceType,
|
|
@@ -13105,8 +13439,10 @@ var index_default = EyePop;
|
|
|
13105
13439
|
ModelTrainingStage,
|
|
13106
13440
|
ModelType,
|
|
13107
13441
|
MotionModel,
|
|
13442
|
+
PointCloud,
|
|
13108
13443
|
PopComponentType,
|
|
13109
13444
|
PredictionVersion,
|
|
13445
|
+
QUATERNION_TOLERANCE,
|
|
13110
13446
|
Semaphore,
|
|
13111
13447
|
Stream,
|
|
13112
13448
|
TaskMode,
|
|
@@ -13125,12 +13461,18 @@ var index_default = EyePop;
|
|
|
13125
13461
|
WorkflowPhase,
|
|
13126
13462
|
accessTokenCredential,
|
|
13127
13463
|
apiKeyCredential,
|
|
13464
|
+
cloudOfDepth,
|
|
13465
|
+
cloudOfObject,
|
|
13466
|
+
cloudsOfPrediction,
|
|
13128
13467
|
decodeDepthMap,
|
|
13468
|
+
decodePointCloud,
|
|
13129
13469
|
encodeMultipartFormData,
|
|
13130
13470
|
getBaseUrl,
|
|
13131
13471
|
randomMultipartBoundary,
|
|
13132
13472
|
readableStreamFromString,
|
|
13133
|
-
resolveAuth
|
|
13473
|
+
resolveAuth,
|
|
13474
|
+
validateCamera,
|
|
13475
|
+
validatePop
|
|
13134
13476
|
});
|
|
13135
13477
|
/*! Bundled license information:
|
|
13136
13478
|
|