web-sdk-pp-detection 0.1.1 → 0.2.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 +20 -8
- package/dist/browser-global.js +214 -23
- package/dist/browser-global.js.map +1 -1
- package/dist/index.d.ts +29 -3
- package/dist/index.js +214 -23
- package/dist/index.js.map +1 -1
- package/dist/inference.worker.js +10 -2
- package/dist/inference.worker.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -228,6 +228,12 @@ interface PPDetectionFallback {
|
|
|
228
228
|
readonly variantId: string;
|
|
229
229
|
}
|
|
230
230
|
interface PPDetectionRuntimeInfo {
|
|
231
|
+
readonly runtimeVersion?: string | null;
|
|
232
|
+
readonly environment?: Readonly<{
|
|
233
|
+
userAgent: string | null;
|
|
234
|
+
platform: string | null;
|
|
235
|
+
capturedAt: string;
|
|
236
|
+
}>;
|
|
231
237
|
readonly requestedBackend: BackendPreference;
|
|
232
238
|
readonly backend: Backend;
|
|
233
239
|
readonly precision: Precision;
|
|
@@ -252,6 +258,7 @@ interface PPDetectionModelSourceInfo {
|
|
|
252
258
|
readonly sha256: string;
|
|
253
259
|
}
|
|
254
260
|
interface PPDetectionLoadTimings {
|
|
261
|
+
readonly modelSource?: "network" | "cache" | "memory";
|
|
255
262
|
readonly modelDownloadMs?: number;
|
|
256
263
|
readonly modelCacheReadMs?: number;
|
|
257
264
|
readonly integrityMs?: number;
|
|
@@ -418,6 +425,9 @@ interface OrtInferenceSession {
|
|
|
418
425
|
interface OrtModule {
|
|
419
426
|
readonly env: {
|
|
420
427
|
readonly wasm?: Record<string, unknown>;
|
|
428
|
+
readonly versions?: {
|
|
429
|
+
readonly web?: string;
|
|
430
|
+
};
|
|
421
431
|
};
|
|
422
432
|
readonly InferenceSession: {
|
|
423
433
|
create(model: ArrayBuffer, options: Record<string, unknown>): Promise<OrtInferenceSession>;
|
|
@@ -425,6 +435,7 @@ interface OrtModule {
|
|
|
425
435
|
readonly Tensor?: new (type: string, data: unknown, dims: readonly number[]) => unknown;
|
|
426
436
|
}
|
|
427
437
|
interface OrtSessionHandle {
|
|
438
|
+
readonly runtimeVersion?: string | null;
|
|
428
439
|
readonly plan: ExecutionPlan;
|
|
429
440
|
readonly sessionMs: number;
|
|
430
441
|
run(feeds: Record<string, unknown>, options?: {
|
|
@@ -522,11 +533,16 @@ interface CacheEstimate {
|
|
|
522
533
|
readonly entries: number;
|
|
523
534
|
}
|
|
524
535
|
interface ModelCache {
|
|
536
|
+
readonly scope?: object;
|
|
525
537
|
get(key: string): Promise<ArrayBuffer | undefined>;
|
|
526
538
|
put(key: string, bytes: ArrayBuffer): Promise<void>;
|
|
527
539
|
clearCurrent(key: string): Promise<void>;
|
|
528
540
|
clearAll(): Promise<void>;
|
|
529
541
|
estimate(): Promise<CacheEstimate>;
|
|
542
|
+
list?(): Promise<readonly {
|
|
543
|
+
key: string;
|
|
544
|
+
bytes: number;
|
|
545
|
+
}[]>;
|
|
530
546
|
close?(): Promise<void> | void;
|
|
531
547
|
}
|
|
532
548
|
|
|
@@ -559,6 +575,7 @@ interface LoadedManagedModel {
|
|
|
559
575
|
declare class ModelManager {
|
|
560
576
|
private readonly fetcher?;
|
|
561
577
|
private readonly cache;
|
|
578
|
+
private readonly coordinator;
|
|
562
579
|
private readonly lifecycle;
|
|
563
580
|
private readonly activeLoads;
|
|
564
581
|
private currentKey?;
|
|
@@ -569,8 +586,8 @@ declare class ModelManager {
|
|
|
569
586
|
load(options: LoadManagedModelOptions): Promise<LoadedManagedModel>;
|
|
570
587
|
private loadActive;
|
|
571
588
|
estimate(): Promise<CacheEstimate>;
|
|
572
|
-
getCacheEstimate(): Promise<CacheEstimate>;
|
|
573
|
-
clearCurrentModelCache(): Promise<void>;
|
|
589
|
+
getCacheEstimate(model?: ModelIdentity): Promise<CacheEstimate>;
|
|
590
|
+
clearCurrentModelCache(model?: ModelIdentity): Promise<void>;
|
|
574
591
|
clearAllCache(): Promise<void>;
|
|
575
592
|
dispose(): Promise<void>;
|
|
576
593
|
}
|
|
@@ -583,6 +600,10 @@ declare class MemoryModelCache implements ModelCache {
|
|
|
583
600
|
clearAll(): Promise<void>;
|
|
584
601
|
estimate(): Promise<CacheEstimate>;
|
|
585
602
|
close(): Promise<void>;
|
|
603
|
+
list(): Promise<readonly {
|
|
604
|
+
key: string;
|
|
605
|
+
bytes: number;
|
|
606
|
+
}[]>;
|
|
586
607
|
}
|
|
587
608
|
|
|
588
609
|
interface IndexedDBModelCacheOptions {
|
|
@@ -590,6 +611,7 @@ interface IndexedDBModelCacheOptions {
|
|
|
590
611
|
readonly databaseName?: string;
|
|
591
612
|
}
|
|
592
613
|
declare class IndexedDBModelCache implements ModelCache {
|
|
614
|
+
readonly scope: object;
|
|
593
615
|
private readonly factory;
|
|
594
616
|
private readonly databaseName;
|
|
595
617
|
private database?;
|
|
@@ -600,6 +622,10 @@ declare class IndexedDBModelCache implements ModelCache {
|
|
|
600
622
|
clearAll(): Promise<void>;
|
|
601
623
|
estimate(): Promise<CacheEstimate>;
|
|
602
624
|
close(): Promise<void>;
|
|
625
|
+
list(): Promise<readonly {
|
|
626
|
+
key: string;
|
|
627
|
+
bytes: number;
|
|
628
|
+
}[]>;
|
|
603
629
|
private open;
|
|
604
630
|
private request;
|
|
605
631
|
}
|
|
@@ -607,7 +633,7 @@ declare class IndexedDBModelCache implements ModelCache {
|
|
|
607
633
|
declare global {
|
|
608
634
|
var __PPDETECTION_SCRIPT_URL__: string | undefined;
|
|
609
635
|
}
|
|
610
|
-
declare const CURRENT_SDK_VERSION = "0.
|
|
636
|
+
declare const CURRENT_SDK_VERSION = "0.2.0";
|
|
611
637
|
|
|
612
638
|
declare function probePPDetectionCapabilities(options?: CapabilityProbeOptions): DetectionCapabilities;
|
|
613
639
|
|
package/dist/index.js
CHANGED
|
@@ -622,7 +622,11 @@ var PPDetectionDetectorImplementation = class {
|
|
|
622
622
|
original: { width: decoded.width, height: decoded.height }
|
|
623
623
|
},
|
|
624
624
|
model: this.model,
|
|
625
|
-
runtime:
|
|
625
|
+
runtime: {
|
|
626
|
+
...this.runtime,
|
|
627
|
+
fallbacks: this.runtime.fallbacks.map((fallback) => ({ ...fallback })),
|
|
628
|
+
...this.runtime.environment ? { environment: { ...this.runtime.environment } } : {}
|
|
629
|
+
},
|
|
626
630
|
timings: {
|
|
627
631
|
decodeMs: decoded.decodeMs,
|
|
628
632
|
preprocessMs,
|
|
@@ -1115,8 +1119,84 @@ function adaptModelManifest(manifest) {
|
|
|
1115
1119
|
});
|
|
1116
1120
|
}
|
|
1117
1121
|
|
|
1122
|
+
// src/cache/coordination.ts
|
|
1123
|
+
var CacheCoordinator = class {
|
|
1124
|
+
caches = /* @__PURE__ */ new Map();
|
|
1125
|
+
generation = 0;
|
|
1126
|
+
keys = /* @__PURE__ */ new Map();
|
|
1127
|
+
pending = Promise.resolve();
|
|
1128
|
+
guard(key) {
|
|
1129
|
+
const generation = this.generation;
|
|
1130
|
+
const keyGeneration = this.keys.get(key) ?? 0;
|
|
1131
|
+
this.keys.set(key, keyGeneration);
|
|
1132
|
+
return () => generation === this.generation && keyGeneration === (this.keys.get(key) ?? 0);
|
|
1133
|
+
}
|
|
1134
|
+
run(operation) {
|
|
1135
|
+
const pending = this.pending.then(operation);
|
|
1136
|
+
this.pending = pending.catch(() => void 0);
|
|
1137
|
+
return pending;
|
|
1138
|
+
}
|
|
1139
|
+
clear(key, matches) {
|
|
1140
|
+
if (matches) {
|
|
1141
|
+
for (const [candidate, generation] of this.keys) {
|
|
1142
|
+
if (matches(candidate)) this.keys.set(candidate, generation + 1);
|
|
1143
|
+
}
|
|
1144
|
+
} else if (key === void 0) this.generation += 1;
|
|
1145
|
+
else this.keys.set(key, (this.keys.get(key) ?? 0) + 1);
|
|
1146
|
+
return this.run(async () => {
|
|
1147
|
+
const outcomes = await Promise.allSettled(
|
|
1148
|
+
[...this.caches.keys()].map(async (cache) => {
|
|
1149
|
+
if (matches && cache.list) {
|
|
1150
|
+
for (const entry of await cache.list()) {
|
|
1151
|
+
if (matches(entry.key)) await cache.clearCurrent(entry.key);
|
|
1152
|
+
}
|
|
1153
|
+
} else if (key === void 0) await cache.clearAll();
|
|
1154
|
+
else await cache.clearCurrent(key);
|
|
1155
|
+
})
|
|
1156
|
+
);
|
|
1157
|
+
const failure = outcomes.find((outcome) => outcome.status === "rejected");
|
|
1158
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
unregister(cache) {
|
|
1162
|
+
const count = this.caches.get(cache) ?? 0;
|
|
1163
|
+
if (count > 1) {
|
|
1164
|
+
this.caches.set(cache, count - 1);
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
this.caches.delete(cache);
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
var coordinators = /* @__PURE__ */ new WeakMap();
|
|
1172
|
+
function coordinateCache(cache) {
|
|
1173
|
+
const scope = cache.scope ?? cache;
|
|
1174
|
+
let coordinator = coordinators.get(scope);
|
|
1175
|
+
if (!coordinator) {
|
|
1176
|
+
coordinator = new CacheCoordinator();
|
|
1177
|
+
coordinators.set(scope, coordinator);
|
|
1178
|
+
}
|
|
1179
|
+
coordinator.caches.set(cache, (coordinator.caches.get(cache) ?? 0) + 1);
|
|
1180
|
+
return coordinator;
|
|
1181
|
+
}
|
|
1182
|
+
var databaseScopes = /* @__PURE__ */ new WeakMap();
|
|
1183
|
+
function databaseScope(factory, name) {
|
|
1184
|
+
let scopes = databaseScopes.get(factory);
|
|
1185
|
+
if (!scopes) {
|
|
1186
|
+
scopes = /* @__PURE__ */ new Map();
|
|
1187
|
+
databaseScopes.set(factory, scopes);
|
|
1188
|
+
}
|
|
1189
|
+
let scope = scopes.get(name);
|
|
1190
|
+
if (!scope) {
|
|
1191
|
+
scope = {};
|
|
1192
|
+
scopes.set(name, scope);
|
|
1193
|
+
}
|
|
1194
|
+
return scope;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1118
1197
|
// src/cache/indexeddb-cache.ts
|
|
1119
1198
|
var IndexedDBModelCache = class {
|
|
1199
|
+
scope;
|
|
1120
1200
|
factory;
|
|
1121
1201
|
databaseName;
|
|
1122
1202
|
database;
|
|
@@ -1125,6 +1205,7 @@ var IndexedDBModelCache = class {
|
|
|
1125
1205
|
if (!factory) throw new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 IndexedDB");
|
|
1126
1206
|
this.factory = factory;
|
|
1127
1207
|
this.databaseName = options.databaseName ?? "web-sdk-pp-detection-models-v1";
|
|
1208
|
+
this.scope = databaseScope(factory, this.databaseName);
|
|
1128
1209
|
}
|
|
1129
1210
|
async get(key) {
|
|
1130
1211
|
const record3 = await this.request(
|
|
@@ -1178,6 +1259,24 @@ var IndexedDBModelCache = class {
|
|
|
1178
1259
|
(await this.database).close();
|
|
1179
1260
|
this.database = void 0;
|
|
1180
1261
|
}
|
|
1262
|
+
async list() {
|
|
1263
|
+
const database = await this.open();
|
|
1264
|
+
return await new Promise((resolve, reject) => {
|
|
1265
|
+
const transaction = database.transaction("models", "readonly");
|
|
1266
|
+
const request = transaction.objectStore("models").openCursor();
|
|
1267
|
+
const entries = [];
|
|
1268
|
+
request.onerror = () => reject(request.error ?? new Error("\u8BFB\u53D6\u7F13\u5B58\u5BB9\u91CF\u5931\u8D25"));
|
|
1269
|
+
request.onsuccess = () => {
|
|
1270
|
+
const cursor = request.result;
|
|
1271
|
+
if (!cursor) return;
|
|
1272
|
+
const record3 = cursor.value;
|
|
1273
|
+
entries.push({ key: record3.key, bytes: record3.size });
|
|
1274
|
+
cursor.continue();
|
|
1275
|
+
};
|
|
1276
|
+
transaction.oncomplete = () => resolve(entries);
|
|
1277
|
+
transaction.onabort = () => reject(transaction.error ?? new Error("\u7F13\u5B58\u5BB9\u91CF\u4E8B\u52A1\u4E2D\u6B62"));
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1181
1280
|
open() {
|
|
1182
1281
|
if (this.database) return this.database;
|
|
1183
1282
|
this.database = new Promise((resolve, reject) => {
|
|
@@ -1247,6 +1346,11 @@ var MemoryModelCache = class {
|
|
|
1247
1346
|
this.entries.clear();
|
|
1248
1347
|
return Promise.resolve();
|
|
1249
1348
|
}
|
|
1349
|
+
list() {
|
|
1350
|
+
return Promise.resolve(
|
|
1351
|
+
[...this.entries].map(([key, bytes]) => ({ key, bytes: bytes.byteLength }))
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1250
1354
|
};
|
|
1251
1355
|
|
|
1252
1356
|
// src/cache/model-cache.ts
|
|
@@ -1254,9 +1358,11 @@ var TieredModelCache = class {
|
|
|
1254
1358
|
constructor(memory, persistent) {
|
|
1255
1359
|
this.memory = memory;
|
|
1256
1360
|
this.persistent = persistent;
|
|
1361
|
+
this.scope = persistent?.scope ?? persistent ?? memory;
|
|
1257
1362
|
}
|
|
1258
1363
|
memory;
|
|
1259
1364
|
persistent;
|
|
1365
|
+
scope;
|
|
1260
1366
|
async get(key) {
|
|
1261
1367
|
const memoryValue = await this.memory.get(key);
|
|
1262
1368
|
if (memoryValue) return memoryValue;
|
|
@@ -1279,6 +1385,13 @@ var TieredModelCache = class {
|
|
|
1279
1385
|
estimate() {
|
|
1280
1386
|
return this.persistent?.estimate() ?? this.memory.estimate();
|
|
1281
1387
|
}
|
|
1388
|
+
async list() {
|
|
1389
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1390
|
+
for (const cache of [this.memory, this.persistent]) {
|
|
1391
|
+
for (const entry of await cache?.list?.() ?? []) entries.set(entry.key, entry);
|
|
1392
|
+
}
|
|
1393
|
+
return [...entries.values()];
|
|
1394
|
+
}
|
|
1282
1395
|
async close() {
|
|
1283
1396
|
await this.memory.close?.();
|
|
1284
1397
|
await this.persistent?.close?.();
|
|
@@ -1488,6 +1601,14 @@ function resolveModelAsset(selection, manifest) {
|
|
|
1488
1601
|
|
|
1489
1602
|
// src/model/model-manager.ts
|
|
1490
1603
|
var SDK_CACHE_NAMESPACE = "web-sdk-pp-detection:cache-v1";
|
|
1604
|
+
function matchesModel(key, model) {
|
|
1605
|
+
try {
|
|
1606
|
+
const parts = JSON.parse(key);
|
|
1607
|
+
return Array.isArray(parts) && parts[0] === SDK_CACHE_NAMESPACE && (model === void 0 || parts[1] === model.id && parts[2] === model.version);
|
|
1608
|
+
} catch {
|
|
1609
|
+
return false;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1491
1612
|
function now2() {
|
|
1492
1613
|
return globalThis.performance?.now() ?? Date.now();
|
|
1493
1614
|
}
|
|
@@ -1511,6 +1632,7 @@ function throwIfAborted4(signal) {
|
|
|
1511
1632
|
var ModelManager = class {
|
|
1512
1633
|
fetcher;
|
|
1513
1634
|
cache;
|
|
1635
|
+
coordinator;
|
|
1514
1636
|
lifecycle = new AbortController();
|
|
1515
1637
|
activeLoads = /* @__PURE__ */ new Set();
|
|
1516
1638
|
currentKey;
|
|
@@ -1519,6 +1641,7 @@ var ModelManager = class {
|
|
|
1519
1641
|
constructor(options = {}) {
|
|
1520
1642
|
this.fetcher = options.fetcher;
|
|
1521
1643
|
this.cache = createCache(options.cache);
|
|
1644
|
+
this.coordinator = coordinateCache(this.cache);
|
|
1522
1645
|
}
|
|
1523
1646
|
cacheKey(variant3, source2, model = { id: "unknown", version: "unknown" }) {
|
|
1524
1647
|
return JSON.stringify([
|
|
@@ -1557,16 +1680,24 @@ var ModelManager = class {
|
|
|
1557
1680
|
const variant3 = resolveModelVariant(manifest, options.variantId);
|
|
1558
1681
|
const sourceKind2 = options.sourceKind ?? "auto";
|
|
1559
1682
|
const sources = resolveModelSources(variant3, sourceKind2);
|
|
1683
|
+
const guards = new Map(
|
|
1684
|
+
sources.map((source2) => {
|
|
1685
|
+
const key = this.cacheKey(variant3, source2, manifest.model);
|
|
1686
|
+
return [key, this.coordinator.guard(key)];
|
|
1687
|
+
})
|
|
1688
|
+
);
|
|
1560
1689
|
const failures = [];
|
|
1561
1690
|
let lastError;
|
|
1562
1691
|
for (const source2 of sources) {
|
|
1563
1692
|
throwIfAborted4(options.signal);
|
|
1564
1693
|
const asset = { model: manifest.model, variant: variant3, source: source2 };
|
|
1565
1694
|
const cacheKey = this.cacheKey(variant3, source2, manifest.model);
|
|
1695
|
+
this.currentKey = cacheKey;
|
|
1696
|
+
const canMutate = guards.get(cacheKey);
|
|
1566
1697
|
const cacheStarted = now2();
|
|
1567
1698
|
let cached;
|
|
1568
1699
|
try {
|
|
1569
|
-
cached = await this.cache.get(cacheKey);
|
|
1700
|
+
cached = await this.coordinator.run(() => this.cache.get(cacheKey));
|
|
1570
1701
|
} catch (error) {
|
|
1571
1702
|
if (error instanceof PPDetectionError && error.code === "ABORTED") throw error;
|
|
1572
1703
|
throwIfAborted4(options.signal);
|
|
@@ -1577,7 +1708,6 @@ var ModelManager = class {
|
|
|
1577
1708
|
const integrityStarted = now2();
|
|
1578
1709
|
try {
|
|
1579
1710
|
await verifyModelIntegrity(cached, source2, options.signal);
|
|
1580
|
-
this.currentKey = cacheKey;
|
|
1581
1711
|
return {
|
|
1582
1712
|
bytes: cached,
|
|
1583
1713
|
manifest,
|
|
@@ -1591,7 +1721,9 @@ var ModelManager = class {
|
|
|
1591
1721
|
} catch (error) {
|
|
1592
1722
|
if (error instanceof PPDetectionError && error.code === "ABORTED") throw error;
|
|
1593
1723
|
try {
|
|
1594
|
-
await this.
|
|
1724
|
+
await this.coordinator.run(async () => {
|
|
1725
|
+
if (canMutate()) await this.cache.clearCurrent(cacheKey);
|
|
1726
|
+
});
|
|
1595
1727
|
} catch (clearError) {
|
|
1596
1728
|
if (clearError instanceof PPDetectionError && clearError.code === "ABORTED")
|
|
1597
1729
|
throw clearError;
|
|
@@ -1627,11 +1759,12 @@ var ModelManager = class {
|
|
|
1627
1759
|
}
|
|
1628
1760
|
throwIfAborted4(options.signal);
|
|
1629
1761
|
try {
|
|
1630
|
-
await this.
|
|
1762
|
+
await this.coordinator.run(async () => {
|
|
1763
|
+
if (canMutate()) await this.cache.put(cacheKey, loaded.bytes);
|
|
1764
|
+
});
|
|
1631
1765
|
} catch {
|
|
1632
1766
|
}
|
|
1633
1767
|
throwIfAborted4(options.signal);
|
|
1634
|
-
this.currentKey = cacheKey;
|
|
1635
1768
|
return {
|
|
1636
1769
|
bytes: loaded.bytes,
|
|
1637
1770
|
manifest,
|
|
@@ -1656,16 +1789,44 @@ var ModelManager = class {
|
|
|
1656
1789
|
estimate() {
|
|
1657
1790
|
return this.getCacheEstimate();
|
|
1658
1791
|
}
|
|
1659
|
-
getCacheEstimate() {
|
|
1660
|
-
return this.
|
|
1792
|
+
getCacheEstimate(model) {
|
|
1793
|
+
return this.coordinator.run(async () => {
|
|
1794
|
+
if (!this.cache.list) {
|
|
1795
|
+
if (model)
|
|
1796
|
+
throw new PPDetectionError(
|
|
1797
|
+
"CAPABILITY_UNSUPPORTED",
|
|
1798
|
+
"\u81EA\u5B9A\u4E49\u7F13\u5B58\u9700\u5B9E\u73B0 list \u624D\u80FD\u6309\u6A21\u578B\u4F30\u7B97"
|
|
1799
|
+
);
|
|
1800
|
+
return this.cache.estimate();
|
|
1801
|
+
}
|
|
1802
|
+
const unique = /* @__PURE__ */ new Map();
|
|
1803
|
+
for (const cache of this.coordinator.caches.keys()) {
|
|
1804
|
+
for (const entry of await cache.list?.() ?? []) unique.set(entry.key, entry);
|
|
1805
|
+
}
|
|
1806
|
+
const entries = [...unique.values()].filter((entry) => matchesModel(entry.key, model));
|
|
1807
|
+
return {
|
|
1808
|
+
bytes: entries.reduce((sum, entry) => sum + entry.bytes, 0),
|
|
1809
|
+
entries: entries.length
|
|
1810
|
+
};
|
|
1811
|
+
});
|
|
1661
1812
|
}
|
|
1662
|
-
async clearCurrentModelCache() {
|
|
1813
|
+
async clearCurrentModelCache(model) {
|
|
1814
|
+
if (model) {
|
|
1815
|
+
if (!model.id || !model.version)
|
|
1816
|
+
throw new PPDetectionError("INVALID_MANIFEST", "\u7F13\u5B58\u6A21\u578B\u8EAB\u4EFD\u5FC5\u987B\u5305\u542B id \u548C version");
|
|
1817
|
+
if (!this.cache.list)
|
|
1818
|
+
throw new PPDetectionError(
|
|
1819
|
+
"CAPABILITY_UNSUPPORTED",
|
|
1820
|
+
"\u81EA\u5B9A\u4E49\u7F13\u5B58\u9700\u5B9E\u73B0 list \u624D\u80FD\u6309\u6A21\u578B\u6E05\u7406"
|
|
1821
|
+
);
|
|
1822
|
+
await this.coordinator.clear(void 0, (key) => matchesModel(key, model));
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1663
1825
|
if (!this.currentKey) return;
|
|
1664
|
-
await this.
|
|
1826
|
+
await this.coordinator.clear(this.currentKey);
|
|
1665
1827
|
}
|
|
1666
1828
|
async clearAllCache() {
|
|
1667
|
-
await this.
|
|
1668
|
-
this.currentKey = void 0;
|
|
1829
|
+
await this.coordinator.clear(void 0, (key) => matchesModel(key));
|
|
1669
1830
|
}
|
|
1670
1831
|
async dispose() {
|
|
1671
1832
|
if (this.disposePromise) return await this.disposePromise;
|
|
@@ -1674,7 +1835,7 @@ var ModelManager = class {
|
|
|
1674
1835
|
this.disposePromise = (async () => {
|
|
1675
1836
|
await Promise.all([...this.activeLoads]);
|
|
1676
1837
|
this.currentKey = void 0;
|
|
1677
|
-
await this.cache.close?.();
|
|
1838
|
+
if (this.coordinator.unregister(this.cache)) await this.cache.close?.();
|
|
1678
1839
|
})();
|
|
1679
1840
|
await this.disposePromise;
|
|
1680
1841
|
}
|
|
@@ -1688,7 +1849,7 @@ function mapError(error, phase) {
|
|
|
1688
1849
|
if (error instanceof PPDetectionError) return error;
|
|
1689
1850
|
const message = error instanceof Error ? error.message : String(error);
|
|
1690
1851
|
const details = { phase, causeMessage: message };
|
|
1691
|
-
if (
|
|
1852
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
1692
1853
|
return new PPDetectionError("ABORTED", "\u63A8\u7406\u5DF2\u53D6\u6D88", details, { cause: error });
|
|
1693
1854
|
if (/memory|out.of.memory|allocation/i.test(message))
|
|
1694
1855
|
return new PPDetectionError("OUT_OF_MEMORY", "\u8FD0\u884C\u65F6\u5185\u5B58\u4E0D\u8DB3", details, { cause: error });
|
|
@@ -1733,6 +1894,7 @@ async function createOrtSession(modelBytes, plan, options = {}) {
|
|
|
1733
1894
|
return {
|
|
1734
1895
|
plan,
|
|
1735
1896
|
sessionMs,
|
|
1897
|
+
runtimeVersion: ort.env.versions?.web ?? null,
|
|
1736
1898
|
async run(feeds, runOptions = {}) {
|
|
1737
1899
|
if (disposed) throw new PPDetectionError("DISPOSED", "\u4F1A\u8BDD\u5DF2\u91CA\u653E", { phase: "run" });
|
|
1738
1900
|
if (runOptions.signal?.aborted)
|
|
@@ -2051,7 +2213,7 @@ var WorkerBridge = class {
|
|
|
2051
2213
|
};
|
|
2052
2214
|
|
|
2053
2215
|
// src/index.ts
|
|
2054
|
-
var CURRENT_SDK_VERSION = "0.
|
|
2216
|
+
var CURRENT_SDK_VERSION = "0.2.0";
|
|
2055
2217
|
function probePPDetectionCapabilities(options = {}) {
|
|
2056
2218
|
return probeCapabilities(options);
|
|
2057
2219
|
}
|
|
@@ -2146,6 +2308,7 @@ function workerUrl() {
|
|
|
2146
2308
|
return new URL("./inference.worker.js", import.meta.url);
|
|
2147
2309
|
}
|
|
2148
2310
|
async function createPPDetection(options = {}) {
|
|
2311
|
+
const loadStartedAt = now4();
|
|
2149
2312
|
if (options.model === void 0 && options.manifest === void 0)
|
|
2150
2313
|
throw new PPDetectionError("INVALID_MANIFEST", "\u521B\u5EFA PPDetection \u5B9E\u4F8B\u9700\u8981 manifest \u6216 model");
|
|
2151
2314
|
const capabilities = probeCapabilities();
|
|
@@ -2178,7 +2341,6 @@ async function createPPDetection(options = {}) {
|
|
|
2178
2341
|
});
|
|
2179
2342
|
let executor;
|
|
2180
2343
|
try {
|
|
2181
|
-
const loadStartedAt = now4();
|
|
2182
2344
|
options.onProgress?.({ phase: "model", status: "start" });
|
|
2183
2345
|
let modelBytes;
|
|
2184
2346
|
let actualSource;
|
|
@@ -2190,10 +2352,17 @@ async function createPPDetection(options = {}) {
|
|
|
2190
2352
|
throw new PPDetectionError("MODEL_SOURCE_UNAVAILABLE", "\u6A21\u578B\u53D8\u4F53\u6CA1\u6709\u53EF\u7528\u6765\u6E90", {
|
|
2191
2353
|
variantId: variant3.id
|
|
2192
2354
|
});
|
|
2355
|
+
const integrityStartedAt = now4();
|
|
2193
2356
|
await verifyModelIntegrity(memoryData, source2, options.signal);
|
|
2357
|
+
const integrityMs = now4() - integrityStartedAt;
|
|
2194
2358
|
modelBytes = memoryData;
|
|
2195
2359
|
actualSource = source2;
|
|
2196
|
-
loadTimings = {
|
|
2360
|
+
loadTimings = {
|
|
2361
|
+
sessionMs: 0,
|
|
2362
|
+
totalMs: now4() - loadStartedAt,
|
|
2363
|
+
integrityMs,
|
|
2364
|
+
modelSource: "memory"
|
|
2365
|
+
};
|
|
2197
2366
|
} else {
|
|
2198
2367
|
const loaded = await modelManager.load({
|
|
2199
2368
|
manifest: runtimeManifest,
|
|
@@ -2205,20 +2374,26 @@ async function createPPDetection(options = {}) {
|
|
|
2205
2374
|
modelBytes = loaded.bytes;
|
|
2206
2375
|
variant3 = loaded.variant;
|
|
2207
2376
|
actualSource = loaded.source;
|
|
2208
|
-
loadTimings = {
|
|
2377
|
+
loadTimings = {
|
|
2378
|
+
...loaded.timings,
|
|
2379
|
+
sessionMs: 0,
|
|
2380
|
+
totalMs: now4() - loadStartedAt,
|
|
2381
|
+
modelSource: loaded.fromCache ? "cache" : "network"
|
|
2382
|
+
};
|
|
2209
2383
|
}
|
|
2210
2384
|
options.onProgress?.({ phase: "model", status: "complete" });
|
|
2211
2385
|
const fallbacks = [];
|
|
2212
2386
|
const createExecutorForPlan = async (candidatePlan) => {
|
|
2213
2387
|
options.onProgress?.({ phase: "session", status: "start" });
|
|
2214
2388
|
let bridge;
|
|
2389
|
+
const sessionStartedAt = now4();
|
|
2215
2390
|
try {
|
|
2216
2391
|
if (candidatePlan.executionMode === "worker") {
|
|
2217
2392
|
if (typeof Worker !== "function")
|
|
2218
2393
|
throw new PPDetectionError("CAPABILITY_UNSUPPORTED", "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 Worker");
|
|
2219
2394
|
const worker = new Worker(workerUrl(), { type: "module" });
|
|
2220
2395
|
bridge = new WorkerBridge(worker);
|
|
2221
|
-
await bridge.load(modelBytes.slice(0), candidatePlan, {
|
|
2396
|
+
const metadata = await bridge.load(modelBytes.slice(0), candidatePlan, {
|
|
2222
2397
|
onProgress: (event) => options.onProgress?.({
|
|
2223
2398
|
phase: "session",
|
|
2224
2399
|
status: event.status
|
|
@@ -2228,6 +2403,7 @@ async function createPPDetection(options = {}) {
|
|
|
2228
2403
|
numThreads: options.ort?.wasm?.numThreads
|
|
2229
2404
|
}
|
|
2230
2405
|
});
|
|
2406
|
+
runtimeVersion = typeof metadata === "object" && metadata !== null && "runtimeVersion" in metadata && typeof metadata.runtimeVersion === "string" ? metadata.runtimeVersion : null;
|
|
2231
2407
|
const activeBridge = bridge;
|
|
2232
2408
|
options.onProgress?.({ phase: "session", status: "complete" });
|
|
2233
2409
|
return {
|
|
@@ -2245,7 +2421,7 @@ async function createPPDetection(options = {}) {
|
|
|
2245
2421
|
wasmPaths: options.ort?.wasm?.paths,
|
|
2246
2422
|
numThreads: options.ort?.wasm?.numThreads
|
|
2247
2423
|
});
|
|
2248
|
-
|
|
2424
|
+
runtimeVersion = session.runtimeVersion ?? null;
|
|
2249
2425
|
options.onProgress?.({ phase: "session", status: "complete" });
|
|
2250
2426
|
return {
|
|
2251
2427
|
run(input, signal) {
|
|
@@ -2269,10 +2445,13 @@ async function createPPDetection(options = {}) {
|
|
|
2269
2445
|
{ phase: "create", causeMessage: message },
|
|
2270
2446
|
{ cause: error }
|
|
2271
2447
|
);
|
|
2448
|
+
} finally {
|
|
2449
|
+
sessionMs += now4() - sessionStartedAt;
|
|
2272
2450
|
}
|
|
2273
2451
|
};
|
|
2274
2452
|
let selectedPlan = plan;
|
|
2275
2453
|
let sessionMs = 0;
|
|
2454
|
+
let runtimeVersion = null;
|
|
2276
2455
|
let selectedCandidateIndex = -1;
|
|
2277
2456
|
for (const [candidateIndex, candidate] of plan.candidates.entries()) {
|
|
2278
2457
|
const candidatePlan = {
|
|
@@ -2314,6 +2493,12 @@ async function createPPDetection(options = {}) {
|
|
|
2314
2493
|
}
|
|
2315
2494
|
if (!executor) throw new PPDetectionError("SESSION_CREATE_FAILED", "\u65E0\u6CD5\u521B\u5EFA\u68C0\u6D4B Session");
|
|
2316
2495
|
const runtime = {
|
|
2496
|
+
runtimeVersion,
|
|
2497
|
+
environment: {
|
|
2498
|
+
userAgent: globalThis.navigator?.userAgent ?? null,
|
|
2499
|
+
platform: globalThis.navigator?.platform ?? null,
|
|
2500
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2501
|
+
},
|
|
2317
2502
|
requestedBackend: options.backend ?? "auto",
|
|
2318
2503
|
backend: selectedPlan.actualBackend,
|
|
2319
2504
|
precision: selectedPlan.actualPrecision,
|
|
@@ -2324,8 +2509,9 @@ async function createPPDetection(options = {}) {
|
|
|
2324
2509
|
let activeExecutor = executor;
|
|
2325
2510
|
const fallbackExecutor = {
|
|
2326
2511
|
async run(input, signal) {
|
|
2512
|
+
const attemptInput = runtime.mode === "worker" && options.allowFallback === true && selectedCandidateIndex < plan.candidates.length - 1 ? { ...input, data: input.data.slice() } : input;
|
|
2327
2513
|
try {
|
|
2328
|
-
return await activeExecutor.run(
|
|
2514
|
+
return await activeExecutor.run(attemptInput, signal);
|
|
2329
2515
|
} catch (error) {
|
|
2330
2516
|
if (options.allowFallback !== true || selectedCandidateIndex < 0 || selectedCandidateIndex >= plan.candidates.length - 1) {
|
|
2331
2517
|
throw error;
|
|
@@ -2350,6 +2536,7 @@ async function createPPDetection(options = {}) {
|
|
|
2350
2536
|
runtime.backend = nextPlan.actualBackend;
|
|
2351
2537
|
runtime.precision = nextPlan.actualPrecision;
|
|
2352
2538
|
runtime.mode = nextPlan.executionMode;
|
|
2539
|
+
runtime.runtimeVersion = runtimeVersion;
|
|
2353
2540
|
const fallback = {
|
|
2354
2541
|
cause: mapped.cause ?? mapped,
|
|
2355
2542
|
code: mapped.code,
|
|
@@ -2381,6 +2568,7 @@ async function createPPDetection(options = {}) {
|
|
|
2381
2568
|
disposeResources: () => modelManager.dispose()
|
|
2382
2569
|
});
|
|
2383
2570
|
await detector.load({ signal: options.signal });
|
|
2571
|
+
loadTimings.totalMs = now4() - loadStartedAt;
|
|
2384
2572
|
options.onProgress?.({ phase: "ready", status: "complete" });
|
|
2385
2573
|
return detector;
|
|
2386
2574
|
} catch (error) {
|
|
@@ -2397,8 +2585,11 @@ async function createPPDetection(options = {}) {
|
|
|
2397
2585
|
}
|
|
2398
2586
|
async function clearModelCache() {
|
|
2399
2587
|
const manager = new ModelManager();
|
|
2400
|
-
|
|
2401
|
-
|
|
2588
|
+
try {
|
|
2589
|
+
await manager.clearAllCache();
|
|
2590
|
+
} finally {
|
|
2591
|
+
await manager.dispose();
|
|
2592
|
+
}
|
|
2402
2593
|
}
|
|
2403
2594
|
|
|
2404
2595
|
export { CURRENT_SDK_VERSION, IndexedDBModelCache, MemoryModelCache, ModelManager, PPDetectionError, adaptModelManifest, clearModelCache, createOrtSession, createPPDetection, loadModelAsset, parseDetectionManifest, parseModelManifest, probeCapabilities, probePPDetectionCapabilities, resolveModelAsset, selectExecutionPlan };
|