@eyepop.ai/eyepop 3.26.0-rc.1 → 3.26.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/dist/eyepop.index.d.mts +96 -5
- package/dist/eyepop.index.d.ts +96 -5
- package/dist/eyepop.index.js +183 -52
- package/dist/eyepop.index.js.map +1 -1
- package/dist/eyepop.index.mjs +181 -52
- package/dist/eyepop.index.mjs.map +1 -1
- package/dist/eyepop.min.js +1 -1
- package/package.json +1 -1
package/dist/eyepop.index.js
CHANGED
|
@@ -8722,6 +8722,8 @@ __export(index_exports, {
|
|
|
8722
8722
|
UploadJob: () => UploadJob,
|
|
8723
8723
|
UserReview: () => UserReview,
|
|
8724
8724
|
VideoMode: () => VideoMode,
|
|
8725
|
+
VlmAbilityModeError: () => VlmAbilityModeError,
|
|
8726
|
+
VlmAbilityModeErrorReason: () => VlmAbilityModeErrorReason,
|
|
8725
8727
|
VlmAbilityStatus: () => VlmAbilityStatus,
|
|
8726
8728
|
WebrtcBase: () => WebrtcBase,
|
|
8727
8729
|
WebrtcWhep: () => WebrtcWhep,
|
|
@@ -9044,14 +9046,25 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
9044
9046
|
}
|
|
9045
9047
|
|
|
9046
9048
|
// endpoint.ts
|
|
9049
|
+
var ACCOUNT_CLAIM = "https://ident.eyepop.ai/account-uuid";
|
|
9050
|
+
var NOT_EXCHANGEABLE = ["API key or user login required", "API key authentication required for token refresh"];
|
|
9051
|
+
function carriesAccount(token) {
|
|
9052
|
+
try {
|
|
9053
|
+
const payload = (token.split(".")[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
|
|
9054
|
+
return Boolean(JSON.parse(atob(payload))?.[ACCOUNT_CLAIM]);
|
|
9055
|
+
} catch {
|
|
9056
|
+
return false;
|
|
9057
|
+
}
|
|
9058
|
+
}
|
|
9047
9059
|
var Endpoint = class {
|
|
9048
9060
|
constructor(options) {
|
|
9061
|
+
this._exchanging = null;
|
|
9049
9062
|
this._options = options;
|
|
9050
9063
|
this._token = null;
|
|
9051
9064
|
this._expire_token_time = null;
|
|
9052
9065
|
this._client = null;
|
|
9053
9066
|
this._statusRetryHandlers = /* @__PURE__ */ new Map();
|
|
9054
|
-
this._statusRetryHandlers.set(401, this.statusHandler401);
|
|
9067
|
+
this._statusRetryHandlers.set(401, (statusCode, failedToken) => this.statusHandler401(statusCode, failedToken));
|
|
9055
9068
|
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9056
9069
|
this._state = "Idle" /* Idle */;
|
|
9057
9070
|
this._message = null;
|
|
@@ -9067,7 +9080,7 @@ var Endpoint = class {
|
|
|
9067
9080
|
}
|
|
9068
9081
|
setStatusRetryHandlers(statusRetryHandlers = void 0) {
|
|
9069
9082
|
this._statusRetryHandlers = new Map(statusRetryHandlers);
|
|
9070
|
-
this._statusRetryHandlers.set(401, this.statusHandler401);
|
|
9083
|
+
this._statusRetryHandlers.set(401, (statusCode, failedToken) => this.statusHandler401(statusCode, failedToken));
|
|
9071
9084
|
}
|
|
9072
9085
|
eyepopUrl() {
|
|
9073
9086
|
if (this._options.eyepopUrl) {
|
|
@@ -9164,12 +9177,15 @@ var Endpoint = class {
|
|
|
9164
9177
|
validUntil: this._expire_token_time * 1e3
|
|
9165
9178
|
};
|
|
9166
9179
|
}
|
|
9167
|
-
statusHandler401(_statusCode) {
|
|
9168
|
-
this._token
|
|
9169
|
-
|
|
9180
|
+
statusHandler401(_statusCode, failedToken = this._token) {
|
|
9181
|
+
if (this._token === failedToken) {
|
|
9182
|
+
this._token = null;
|
|
9183
|
+
this._expire_token_time = null;
|
|
9184
|
+
}
|
|
9170
9185
|
}
|
|
9171
9186
|
async fetchWithRetry(fetcher, retries = 1) {
|
|
9172
9187
|
while (true) {
|
|
9188
|
+
const sentToken = this._token ?? void 0;
|
|
9173
9189
|
try {
|
|
9174
9190
|
const response = await fetcher();
|
|
9175
9191
|
if (response.ok) {
|
|
@@ -9177,7 +9193,7 @@ var Endpoint = class {
|
|
|
9177
9193
|
} else {
|
|
9178
9194
|
const handler = this._statusRetryHandlers.get(response.status);
|
|
9179
9195
|
if (handler != null) {
|
|
9180
|
-
handler(response.status);
|
|
9196
|
+
handler(response.status, sentToken);
|
|
9181
9197
|
if (retries--) {
|
|
9182
9198
|
this._requestLogger.info("received %d response, retry", response.status);
|
|
9183
9199
|
} else {
|
|
@@ -9211,54 +9227,75 @@ var Endpoint = class {
|
|
|
9211
9227
|
}
|
|
9212
9228
|
return `Bearer ${await this.currentAccessToken()}`;
|
|
9213
9229
|
}
|
|
9230
|
+
async exchange(client, credential, accountUuid) {
|
|
9231
|
+
const query = accountUuid ? `?account_uuid=${encodeURIComponent(accountUuid)}` : "";
|
|
9232
|
+
return await client.fetch(`${this.eyepopUrl()}/v1/auth/authenticate${query}`, {
|
|
9233
|
+
method: "POST",
|
|
9234
|
+
headers: { Authorization: `Bearer ${credential}` }
|
|
9235
|
+
});
|
|
9236
|
+
}
|
|
9237
|
+
async storeExchangedToken(response, now) {
|
|
9238
|
+
if (response.status != 200) {
|
|
9239
|
+
const message = await response.text();
|
|
9240
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9241
|
+
}
|
|
9242
|
+
const token = await response.json();
|
|
9243
|
+
this._token = token.access_token;
|
|
9244
|
+
this._expire_token_time = now + token.expires_in - 60;
|
|
9245
|
+
}
|
|
9246
|
+
/**
|
|
9247
|
+
* A token that already carries an account, or that the compute API refuses to exchange
|
|
9248
|
+
* (see NOT_EXCHANGEABLE), is used as is. Any other refusal is raised.
|
|
9249
|
+
*/
|
|
9250
|
+
async exchangeLoginToken(client, loginToken, validUntil, now) {
|
|
9251
|
+
if (!carriesAccount(loginToken)) {
|
|
9252
|
+
const response = await this.exchange(client, loginToken, this._options.accountId);
|
|
9253
|
+
const refusal = response.status == 401 ? await response.clone().text() : "";
|
|
9254
|
+
if (!NOT_EXCHANGEABLE.some((message) => refusal.includes(message))) {
|
|
9255
|
+
await this.storeExchangedToken(response, now);
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
}
|
|
9259
|
+
this._token = loginToken;
|
|
9260
|
+
this._expire_token_time = validUntil;
|
|
9261
|
+
}
|
|
9214
9262
|
async currentAccessToken() {
|
|
9263
|
+
if (!this._token || this._expire_token_time < Date.now() / 1e3) {
|
|
9264
|
+
this._exchanging ?? (this._exchanging = this.authenticate().finally(() => this._exchanging = null));
|
|
9265
|
+
await this._exchanging;
|
|
9266
|
+
}
|
|
9267
|
+
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - Date.now() / 1e3);
|
|
9268
|
+
return this._token;
|
|
9269
|
+
}
|
|
9270
|
+
async authenticate() {
|
|
9215
9271
|
const now = Date.now() / 1e3;
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
} else if (this._options.eyepopUrl) {
|
|
9235
|
-
const credential = apiKeyCredential(auth);
|
|
9236
|
-
if (credential === void 0) {
|
|
9237
|
-
return Promise.reject("no valid auth option");
|
|
9238
|
-
}
|
|
9239
|
-
const headers = { Authorization: `Bearer ${credential}` };
|
|
9240
|
-
const post_url = `${this.eyepopUrl()}/v1/auth/authenticate`;
|
|
9241
|
-
const response = await this._client.fetch(post_url, {
|
|
9242
|
-
method: "POST",
|
|
9243
|
-
headers
|
|
9244
|
-
});
|
|
9245
|
-
if (response.status != 200) {
|
|
9246
|
-
const message = await response.text();
|
|
9247
|
-
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9248
|
-
}
|
|
9249
|
-
const data = await response.json();
|
|
9250
|
-
const token = data;
|
|
9251
|
-
this._token = token.access_token;
|
|
9252
|
-
this._expire_token_time = now + token.expires_in - 60;
|
|
9253
|
-
} else {
|
|
9272
|
+
this.updateState("Authenticating" /* Authenticating */);
|
|
9273
|
+
try {
|
|
9274
|
+
const auth = resolveAuth(this._options);
|
|
9275
|
+
if (!this._client) {
|
|
9276
|
+
return Promise.reject("endpoint not connected");
|
|
9277
|
+
} else if (auth?.isLocal !== void 0) {
|
|
9278
|
+
this._token = "implicit";
|
|
9279
|
+
this._expire_token_time = Number.MAX_VALUE;
|
|
9280
|
+
} else if (auth?.session !== void 0) {
|
|
9281
|
+
return Promise.reject("temporary access token expired");
|
|
9282
|
+
} else if (auth?.oAuth2 !== void 0 && this._options.eyepopUrl) {
|
|
9283
|
+
const login = await authenticateBrowserSession(auth.oAuth2, this._options);
|
|
9284
|
+
await this.exchangeLoginToken(this._client, login.accessToken, login.validUntil / 1e3, now);
|
|
9285
|
+
} else if (accessTokenCredential(auth) !== void 0) {
|
|
9286
|
+
await this.exchangeLoginToken(this._client, accessTokenCredential(auth), Number.MAX_VALUE, now);
|
|
9287
|
+
} else if (this._options.eyepopUrl) {
|
|
9288
|
+
const credential = apiKeyCredential(auth);
|
|
9289
|
+
if (credential === void 0) {
|
|
9254
9290
|
return Promise.reject("no valid auth option");
|
|
9255
9291
|
}
|
|
9256
|
-
|
|
9257
|
-
|
|
9292
|
+
await this.storeExchangedToken(await this.exchange(this._client, credential), now);
|
|
9293
|
+
} else {
|
|
9294
|
+
return Promise.reject("no valid auth option");
|
|
9258
9295
|
}
|
|
9296
|
+
} finally {
|
|
9297
|
+
this.updateState();
|
|
9259
9298
|
}
|
|
9260
|
-
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
|
|
9261
|
-
return this._token;
|
|
9262
9299
|
}
|
|
9263
9300
|
};
|
|
9264
9301
|
|
|
@@ -11808,10 +11845,22 @@ var PipelineJob = class {
|
|
|
11808
11845
|
this.openSource = null;
|
|
11809
11846
|
// Stops the job's source on the pipeline, once it was sent.
|
|
11810
11847
|
this.stopOnPipeline = null;
|
|
11848
|
+
this._milliComputeUnits = void 0;
|
|
11811
11849
|
}
|
|
11812
11850
|
get cancelled() {
|
|
11813
11851
|
return this._cancelled;
|
|
11814
11852
|
}
|
|
11853
|
+
/** The source's milli compute units: the latest total of its `usage` messages and its `end`. */
|
|
11854
|
+
get milliComputeUnits() {
|
|
11855
|
+
return this._milliComputeUnits;
|
|
11856
|
+
}
|
|
11857
|
+
/** Keep a usage's or an end's milliComputeUnits: each carries the source's total so far. */
|
|
11858
|
+
noteMilliComputeUnits(message) {
|
|
11859
|
+
const value = message["milliComputeUnits"];
|
|
11860
|
+
if (Number.isInteger(value) && value >= 0) {
|
|
11861
|
+
this._milliComputeUnits = value;
|
|
11862
|
+
}
|
|
11863
|
+
}
|
|
11815
11864
|
command(id) {
|
|
11816
11865
|
const command = { type: "setSource", id, ...this.source };
|
|
11817
11866
|
if (this.params.componentParams !== void 0) {
|
|
@@ -12389,7 +12438,11 @@ var PipelineBackend = class {
|
|
|
12389
12438
|
case "prediction":
|
|
12390
12439
|
job.predicted(message["prediction"]);
|
|
12391
12440
|
break;
|
|
12441
|
+
case "usage":
|
|
12442
|
+
job.noteMilliComputeUnits(message);
|
|
12443
|
+
break;
|
|
12392
12444
|
case "end":
|
|
12445
|
+
job.noteMilliComputeUnits(message);
|
|
12393
12446
|
if (message["reason"] === "eos") {
|
|
12394
12447
|
return null;
|
|
12395
12448
|
}
|
|
@@ -12953,6 +13006,7 @@ var InferAssetJob = class {
|
|
|
12953
13006
|
constructor(assetUrl, inferRequest, vlmFetch, requestLogger) {
|
|
12954
13007
|
this._response = null;
|
|
12955
13008
|
this._runInfo = null;
|
|
13009
|
+
this._milliComputeUnits = void 0;
|
|
12956
13010
|
this._controller = new AbortController();
|
|
12957
13011
|
this._vlmFetch = vlmFetch;
|
|
12958
13012
|
this._assetUrl = assetUrl;
|
|
@@ -12989,6 +13043,13 @@ var InferAssetJob = class {
|
|
|
12989
13043
|
}
|
|
12990
13044
|
return iterator();
|
|
12991
13045
|
}
|
|
13046
|
+
/**
|
|
13047
|
+
* The milli compute units vlm-server billed for the inference, 0 on a cache hit; undefined before it answered
|
|
13048
|
+
* or when it reported none.
|
|
13049
|
+
*/
|
|
13050
|
+
get milliComputeUnits() {
|
|
13051
|
+
return this._milliComputeUnits;
|
|
13052
|
+
}
|
|
12992
13053
|
start(done) {
|
|
12993
13054
|
this._response = new Promise(async (resolve, reject) => {
|
|
12994
13055
|
try {
|
|
@@ -13013,6 +13074,8 @@ var InferAssetJob = class {
|
|
|
13013
13074
|
const runInfo = response["run_info"];
|
|
13014
13075
|
if (predictions) {
|
|
13015
13076
|
this._runInfo = runInfo;
|
|
13077
|
+
const used = response["milli_compute_units"] ?? response["compute_units"];
|
|
13078
|
+
this._milliComputeUnits = typeof used === "number" ? used : void 0;
|
|
13016
13079
|
resolve(predictions);
|
|
13017
13080
|
break;
|
|
13018
13081
|
} else {
|
|
@@ -13129,6 +13192,70 @@ function omit_nulls(_, value) {
|
|
|
13129
13192
|
}
|
|
13130
13193
|
return value;
|
|
13131
13194
|
}
|
|
13195
|
+
var TASK_EXCLUDED_FIELDS = ["text_prompt", "transform_into", "response_schema"];
|
|
13196
|
+
var VlmAbilityModeErrorReason = /* @__PURE__ */ ((VlmAbilityModeErrorReason2) => {
|
|
13197
|
+
VlmAbilityModeErrorReason2["missing_mode"] = "missing_mode";
|
|
13198
|
+
VlmAbilityModeErrorReason2["unknown_task"] = "unknown_task";
|
|
13199
|
+
VlmAbilityModeErrorReason2["task_excludes_free_form"] = "task_excludes_free_form";
|
|
13200
|
+
VlmAbilityModeErrorReason2["task_without_prompts"] = "task_without_prompts";
|
|
13201
|
+
VlmAbilityModeErrorReason2["prompts_without_task"] = "prompts_without_task";
|
|
13202
|
+
VlmAbilityModeErrorReason2["empty_prompts"] = "empty_prompts";
|
|
13203
|
+
VlmAbilityModeErrorReason2["invalid_prompt"] = "invalid_prompt";
|
|
13204
|
+
return VlmAbilityModeErrorReason2;
|
|
13205
|
+
})(VlmAbilityModeErrorReason || {});
|
|
13206
|
+
var VlmAbilityModeError = class extends Error {
|
|
13207
|
+
constructor(reason, message, fields = []) {
|
|
13208
|
+
super(message);
|
|
13209
|
+
this.name = "VlmAbilityModeError";
|
|
13210
|
+
this.reason = reason;
|
|
13211
|
+
this.fields = fields;
|
|
13212
|
+
}
|
|
13213
|
+
};
|
|
13214
|
+
function isSet(value) {
|
|
13215
|
+
return value !== void 0 && value !== null;
|
|
13216
|
+
}
|
|
13217
|
+
function validateVlmAbilityMode(ability, partial) {
|
|
13218
|
+
const kind = partial ? "VLM ability update" : "VLM ability";
|
|
13219
|
+
const taskSet = isSet(ability.task);
|
|
13220
|
+
const promptsSet = isSet(ability.prompts);
|
|
13221
|
+
if (taskSet && !Object.values(AutoAnnotateTask).includes(ability.task)) {
|
|
13222
|
+
throw new VlmAbilityModeError("unknown_task" /* unknown_task */, `${kind}: unknown task '${String(ability.task)}', expected one of ${Object.values(AutoAnnotateTask).join(", ")}`, [
|
|
13223
|
+
"task"
|
|
13224
|
+
]);
|
|
13225
|
+
}
|
|
13226
|
+
if (taskSet || promptsSet) {
|
|
13227
|
+
const conflicting = TASK_EXCLUDED_FIELDS.filter((field) => isSet(ability[field]));
|
|
13228
|
+
if (conflicting.length > 0) {
|
|
13229
|
+
throw new VlmAbilityModeError(
|
|
13230
|
+
"task_excludes_free_form" /* task_excludes_free_form */,
|
|
13231
|
+
`${kind}: a task derives the prompt and output schema, so ${conflicting.join(", ")} must be unset with task and prompts`,
|
|
13232
|
+
[...conflicting]
|
|
13233
|
+
);
|
|
13234
|
+
}
|
|
13235
|
+
}
|
|
13236
|
+
if (promptsSet) {
|
|
13237
|
+
if (!Array.isArray(ability.prompts) || ability.prompts.length === 0) {
|
|
13238
|
+
throw new VlmAbilityModeError("empty_prompts" /* empty_prompts */, `${kind}: prompts must be a non-empty list of {label, prompt}`, ["prompts"]);
|
|
13239
|
+
}
|
|
13240
|
+
ability.prompts.forEach((entry, i) => {
|
|
13241
|
+
if (!entry || typeof entry.label !== "string" || entry.label.length === 0 || typeof entry.prompt !== "string" || entry.prompt.length === 0) {
|
|
13242
|
+
throw new VlmAbilityModeError("invalid_prompt" /* invalid_prompt */, `${kind}: prompts[${i}] needs a non-empty label and prompt`, [`prompts[${i}]`]);
|
|
13243
|
+
}
|
|
13244
|
+
});
|
|
13245
|
+
}
|
|
13246
|
+
if (partial) {
|
|
13247
|
+
return;
|
|
13248
|
+
}
|
|
13249
|
+
if (taskSet && !promptsSet) {
|
|
13250
|
+
throw new VlmAbilityModeError("task_without_prompts" /* task_without_prompts */, `${kind}: task '${ability.task}' requires a non-empty prompts list of {label, prompt}`, ["prompts"]);
|
|
13251
|
+
}
|
|
13252
|
+
if (!taskSet && promptsSet) {
|
|
13253
|
+
throw new VlmAbilityModeError("prompts_without_task" /* prompts_without_task */, `${kind}: prompts are only used with a task; set task, or use text_prompt for a free-form ability`, ["prompts"]);
|
|
13254
|
+
}
|
|
13255
|
+
if (!taskSet && !(typeof ability.text_prompt === "string" && ability.text_prompt.length > 0)) {
|
|
13256
|
+
throw new VlmAbilityModeError("missing_mode" /* missing_mode */, `${kind}: set either text_prompt (free-form) or task with non-empty prompts`, ["text_prompt", "task"]);
|
|
13257
|
+
}
|
|
13258
|
+
}
|
|
13132
13259
|
var DataEndpoint = class extends Endpoint {
|
|
13133
13260
|
constructor(options) {
|
|
13134
13261
|
super(options);
|
|
@@ -13920,6 +14047,7 @@ var DataEndpoint = class extends Endpoint {
|
|
|
13920
14047
|
});
|
|
13921
14048
|
}
|
|
13922
14049
|
async createVlmAbility(create, vlm_ability_group_uuid) {
|
|
14050
|
+
validateVlmAbilityMode(create, false);
|
|
13923
14051
|
const groupQuery = vlm_ability_group_uuid ? `&vlm_ability_group_uuid=${vlm_ability_group_uuid}` : "";
|
|
13924
14052
|
return this.request(`/vlm_abilities?account_uuid=${this._accountId}${groupQuery}`, {
|
|
13925
14053
|
method: "POST",
|
|
@@ -13938,6 +14066,7 @@ var DataEndpoint = class extends Endpoint {
|
|
|
13938
14066
|
});
|
|
13939
14067
|
}
|
|
13940
14068
|
async updateVlmAbility(vlm_ability_uuid, update) {
|
|
14069
|
+
validateVlmAbilityMode(update, true);
|
|
13941
14070
|
return this.request(`/vlm_abilities/${vlm_ability_uuid}`, {
|
|
13942
14071
|
method: "PATCH",
|
|
13943
14072
|
body: JSON.stringify(update),
|
|
@@ -14536,17 +14665,17 @@ var EyePop;
|
|
|
14536
14665
|
if (typeof auth.oAuth2 === "boolean") {
|
|
14537
14666
|
const oAuth2 = opts.eyepopUrl && opts.eyepopUrl.match(/https:(.*).staging.eyepop.xyz/i) ? {
|
|
14538
14667
|
oAuth2: {
|
|
14539
|
-
domain: "
|
|
14668
|
+
domain: "auth0.eyepop.xyz",
|
|
14540
14669
|
clientId: "jktx3YO2UnbkNPvr05PQWf26t1kNTJyg",
|
|
14541
14670
|
audience: "https://dev-app.eyepop.ai",
|
|
14542
|
-
scope: "
|
|
14671
|
+
scope: "access:inference-api access:datasets"
|
|
14543
14672
|
}
|
|
14544
14673
|
} : {
|
|
14545
14674
|
oAuth2: {
|
|
14546
|
-
domain: "eyepop.
|
|
14675
|
+
domain: "auth0.eyepop.ai",
|
|
14547
14676
|
clientId: "Lb9ubA9Hf3jlaqWLUx8XgA0zvotgViCl",
|
|
14548
14677
|
audience: "https://api.eyepop.ai",
|
|
14549
|
-
scope: "
|
|
14678
|
+
scope: "access:inference-api access:datasets"
|
|
14550
14679
|
}
|
|
14551
14680
|
};
|
|
14552
14681
|
if (opts.oAuth2 !== void 0) {
|
|
@@ -14631,6 +14760,8 @@ var index_default = EyePop;
|
|
|
14631
14760
|
UploadJob,
|
|
14632
14761
|
UserReview,
|
|
14633
14762
|
VideoMode,
|
|
14763
|
+
VlmAbilityModeError,
|
|
14764
|
+
VlmAbilityModeErrorReason,
|
|
14634
14765
|
VlmAbilityStatus,
|
|
14635
14766
|
WebrtcBase,
|
|
14636
14767
|
WebrtcWhep,
|