web-sdk-pp-detection 0.1.0 → 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 +30 -20
- package/dist/browser-global.js +335 -93
- package/dist/browser-global.js.map +1 -1
- package/dist/index.d.ts +29 -3
- package/dist/index.js +335 -93
- package/dist/index.js.map +1 -1
- package/dist/inference.worker.js +14 -5
- package/dist/inference.worker.js.map +1 -1
- package/package.json +1 -1
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
|
}
|
|
@@ -1687,14 +1848,15 @@ function now3() {
|
|
|
1687
1848
|
function mapError(error, phase) {
|
|
1688
1849
|
if (error instanceof PPDetectionError) return error;
|
|
1689
1850
|
const message = error instanceof Error ? error.message : String(error);
|
|
1690
|
-
|
|
1691
|
-
|
|
1851
|
+
const details = { phase, causeMessage: message };
|
|
1852
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
1853
|
+
return new PPDetectionError("ABORTED", "\u63A8\u7406\u5DF2\u53D6\u6D88", details, { cause: error });
|
|
1692
1854
|
if (/memory|out.of.memory|allocation/i.test(message))
|
|
1693
|
-
return new PPDetectionError("OUT_OF_MEMORY", "\u8FD0\u884C\u65F6\u5185\u5B58\u4E0D\u8DB3",
|
|
1855
|
+
return new PPDetectionError("OUT_OF_MEMORY", "\u8FD0\u884C\u65F6\u5185\u5B58\u4E0D\u8DB3", details, { cause: error });
|
|
1694
1856
|
return new PPDetectionError(
|
|
1695
1857
|
phase === "create" ? "SESSION_CREATE_FAILED" : "INFERENCE_FAILED",
|
|
1696
1858
|
phase === "create" ? "\u521B\u5EFA ONNX Runtime \u4F1A\u8BDD\u5931\u8D25" : "ONNX Runtime \u63A8\u7406\u5931\u8D25",
|
|
1697
|
-
|
|
1859
|
+
details,
|
|
1698
1860
|
{ cause: error }
|
|
1699
1861
|
);
|
|
1700
1862
|
}
|
|
@@ -1732,6 +1894,7 @@ async function createOrtSession(modelBytes, plan, options = {}) {
|
|
|
1732
1894
|
return {
|
|
1733
1895
|
plan,
|
|
1734
1896
|
sessionMs,
|
|
1897
|
+
runtimeVersion: ort.env.versions?.web ?? null,
|
|
1735
1898
|
async run(feeds, runOptions = {}) {
|
|
1736
1899
|
if (disposed) throw new PPDetectionError("DISPOSED", "\u4F1A\u8BDD\u5DF2\u91CA\u653E", { phase: "run" });
|
|
1737
1900
|
if (runOptions.signal?.aborted)
|
|
@@ -1852,14 +2015,13 @@ function probeCapabilities(options = {}) {
|
|
|
1852
2015
|
function fail(code, message, details) {
|
|
1853
2016
|
throw new PPDetectionError(code, message, details);
|
|
1854
2017
|
}
|
|
1855
|
-
function candidatesForBackend(requested, capabilities
|
|
2018
|
+
function candidatesForBackend(requested, capabilities) {
|
|
1856
2019
|
if (requested === "wasm") return ["wasm"];
|
|
1857
2020
|
if (requested === "webgpu")
|
|
1858
2021
|
return capabilities.webgpu ? ["webgpu"] : fail("CAPABILITY_UNSUPPORTED", "\u8BF7\u6C42\u7684 webgpu \u4E0D\u53EF\u7528", { requestedBackend: requested });
|
|
1859
2022
|
const available = [];
|
|
1860
2023
|
if (capabilities.webgpu) available.push("webgpu");
|
|
1861
2024
|
available.push("wasm");
|
|
1862
|
-
if (!allowFallback) return available.slice(0, 1);
|
|
1863
2025
|
return available;
|
|
1864
2026
|
}
|
|
1865
2027
|
function selectExecutionPlan(options, capabilities, manifest) {
|
|
@@ -1877,19 +2039,18 @@ function selectExecutionPlan(options, capabilities, manifest) {
|
|
|
1877
2039
|
requestedPrecision
|
|
1878
2040
|
});
|
|
1879
2041
|
}
|
|
1880
|
-
const candidates = candidatesForBackend(
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
if (candidates.length === 0) {
|
|
2042
|
+
const candidates = candidatesForBackend(requestedBackend, capabilities).filter(
|
|
2043
|
+
(backend) => variant3.backends.includes(backend)
|
|
2044
|
+
);
|
|
2045
|
+
const selectedCandidates = options.allowFallback === true ? candidates : candidates.slice(0, 1);
|
|
2046
|
+
if (selectedCandidates.length === 0) {
|
|
1886
2047
|
fail("CAPABILITY_UNSUPPORTED", "\u6CA1\u6709\u4E0E\u6A21\u578B\u53D8\u4F53\u5339\u914D\u7684\u53EF\u7528\u540E\u7AEF", {
|
|
1887
2048
|
requestedBackend,
|
|
1888
2049
|
requestedPrecision,
|
|
1889
2050
|
availableBackends: variant3.backends
|
|
1890
2051
|
});
|
|
1891
2052
|
}
|
|
1892
|
-
const actualBackend =
|
|
2053
|
+
const actualBackend = selectedCandidates[0];
|
|
1893
2054
|
return {
|
|
1894
2055
|
variantId: variant3.id,
|
|
1895
2056
|
requestedBackend,
|
|
@@ -1897,7 +2058,7 @@ function selectExecutionPlan(options, capabilities, manifest) {
|
|
|
1897
2058
|
requestedPrecision,
|
|
1898
2059
|
actualPrecision: variant3.precision,
|
|
1899
2060
|
executionMode,
|
|
1900
|
-
candidates:
|
|
2061
|
+
candidates: selectedCandidates.map((backend) => ({
|
|
1901
2062
|
variantId: variant3.id,
|
|
1902
2063
|
backend,
|
|
1903
2064
|
precision: variant3.precision,
|
|
@@ -2052,7 +2213,7 @@ var WorkerBridge = class {
|
|
|
2052
2213
|
};
|
|
2053
2214
|
|
|
2054
2215
|
// src/index.ts
|
|
2055
|
-
var CURRENT_SDK_VERSION = "0.
|
|
2216
|
+
var CURRENT_SDK_VERSION = "0.2.0";
|
|
2056
2217
|
function probePPDetectionCapabilities(options = {}) {
|
|
2057
2218
|
return probeCapabilities(options);
|
|
2058
2219
|
}
|
|
@@ -2147,6 +2308,7 @@ function workerUrl() {
|
|
|
2147
2308
|
return new URL("./inference.worker.js", import.meta.url);
|
|
2148
2309
|
}
|
|
2149
2310
|
async function createPPDetection(options = {}) {
|
|
2311
|
+
const loadStartedAt = now4();
|
|
2150
2312
|
if (options.model === void 0 && options.manifest === void 0)
|
|
2151
2313
|
throw new PPDetectionError("INVALID_MANIFEST", "\u521B\u5EFA PPDetection \u5B9E\u4F8B\u9700\u8981 manifest \u6216 model");
|
|
2152
2314
|
const capabilities = probeCapabilities();
|
|
@@ -2178,9 +2340,7 @@ async function createPPDetection(options = {}) {
|
|
|
2178
2340
|
cache: options.cache === false ? false : options.cache === "memory" ? "memory" : void 0
|
|
2179
2341
|
});
|
|
2180
2342
|
let executor;
|
|
2181
|
-
let activeBridge;
|
|
2182
2343
|
try {
|
|
2183
|
-
const loadStartedAt = now4();
|
|
2184
2344
|
options.onProgress?.({ phase: "model", status: "start" });
|
|
2185
2345
|
let modelBytes;
|
|
2186
2346
|
let actualSource;
|
|
@@ -2192,10 +2352,17 @@ async function createPPDetection(options = {}) {
|
|
|
2192
2352
|
throw new PPDetectionError("MODEL_SOURCE_UNAVAILABLE", "\u6A21\u578B\u53D8\u4F53\u6CA1\u6709\u53EF\u7528\u6765\u6E90", {
|
|
2193
2353
|
variantId: variant3.id
|
|
2194
2354
|
});
|
|
2355
|
+
const integrityStartedAt = now4();
|
|
2195
2356
|
await verifyModelIntegrity(memoryData, source2, options.signal);
|
|
2357
|
+
const integrityMs = now4() - integrityStartedAt;
|
|
2196
2358
|
modelBytes = memoryData;
|
|
2197
2359
|
actualSource = source2;
|
|
2198
|
-
loadTimings = {
|
|
2360
|
+
loadTimings = {
|
|
2361
|
+
sessionMs: 0,
|
|
2362
|
+
totalMs: now4() - loadStartedAt,
|
|
2363
|
+
integrityMs,
|
|
2364
|
+
modelSource: "memory"
|
|
2365
|
+
};
|
|
2199
2366
|
} else {
|
|
2200
2367
|
const loaded = await modelManager.load({
|
|
2201
2368
|
manifest: runtimeManifest,
|
|
@@ -2207,33 +2374,26 @@ async function createPPDetection(options = {}) {
|
|
|
2207
2374
|
modelBytes = loaded.bytes;
|
|
2208
2375
|
variant3 = loaded.variant;
|
|
2209
2376
|
actualSource = loaded.source;
|
|
2210
|
-
loadTimings = {
|
|
2377
|
+
loadTimings = {
|
|
2378
|
+
...loaded.timings,
|
|
2379
|
+
sessionMs: 0,
|
|
2380
|
+
totalMs: now4() - loadStartedAt,
|
|
2381
|
+
modelSource: loaded.fromCache ? "cache" : "network"
|
|
2382
|
+
};
|
|
2211
2383
|
}
|
|
2212
2384
|
options.onProgress?.({ phase: "model", status: "complete" });
|
|
2213
2385
|
const fallbacks = [];
|
|
2214
|
-
|
|
2215
|
-
let sessionMs = 0;
|
|
2216
|
-
for (const candidate of plan.candidates) {
|
|
2217
|
-
const candidatePlan = {
|
|
2218
|
-
...plan,
|
|
2219
|
-
variantId: candidate.variantId,
|
|
2220
|
-
actualBackend: candidate.backend,
|
|
2221
|
-
actualPrecision: candidate.precision,
|
|
2222
|
-
executionMode: candidate.executionMode,
|
|
2223
|
-
candidates: [candidate]
|
|
2224
|
-
};
|
|
2386
|
+
const createExecutorForPlan = async (candidatePlan) => {
|
|
2225
2387
|
options.onProgress?.({ phase: "session", status: "start" });
|
|
2388
|
+
let bridge;
|
|
2389
|
+
const sessionStartedAt = now4();
|
|
2226
2390
|
try {
|
|
2227
|
-
if (
|
|
2391
|
+
if (candidatePlan.executionMode === "worker") {
|
|
2228
2392
|
if (typeof Worker !== "function")
|
|
2229
2393
|
throw new PPDetectionError("CAPABILITY_UNSUPPORTED", "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 Worker");
|
|
2230
|
-
const worker = new Worker(workerUrl(), {
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
const bridge = new WorkerBridge(worker);
|
|
2234
|
-
activeBridge = bridge;
|
|
2235
|
-
const workerModelBytes = modelBytes.slice(0);
|
|
2236
|
-
await bridge.load(workerModelBytes, candidatePlan, {
|
|
2394
|
+
const worker = new Worker(workerUrl(), { type: "module" });
|
|
2395
|
+
bridge = new WorkerBridge(worker);
|
|
2396
|
+
const metadata = await bridge.load(modelBytes.slice(0), candidatePlan, {
|
|
2237
2397
|
onProgress: (event) => options.onProgress?.({
|
|
2238
2398
|
phase: "session",
|
|
2239
2399
|
status: event.status
|
|
@@ -2243,35 +2403,69 @@ async function createPPDetection(options = {}) {
|
|
|
2243
2403
|
numThreads: options.ort?.wasm?.numThreads
|
|
2244
2404
|
}
|
|
2245
2405
|
});
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
{ signal }
|
|
2251
|
-
);
|
|
2252
|
-
},
|
|
2253
|
-
dispose: () => bridge.dispose()
|
|
2254
|
-
};
|
|
2255
|
-
activeBridge = void 0;
|
|
2256
|
-
} else {
|
|
2257
|
-
const session = await createOrtSession(modelBytes, candidatePlan, {
|
|
2258
|
-
ort: options.ort?.module,
|
|
2259
|
-
wasmPaths: options.ort?.wasm?.paths,
|
|
2260
|
-
numThreads: options.ort?.wasm?.numThreads
|
|
2261
|
-
});
|
|
2262
|
-
sessionMs = session.sessionMs;
|
|
2263
|
-
executor = {
|
|
2406
|
+
runtimeVersion = typeof metadata === "object" && metadata !== null && "runtimeVersion" in metadata && typeof metadata.runtimeVersion === "string" ? metadata.runtimeVersion : null;
|
|
2407
|
+
const activeBridge = bridge;
|
|
2408
|
+
options.onProgress?.({ phase: "session", status: "complete" });
|
|
2409
|
+
return {
|
|
2264
2410
|
run(input, signal) {
|
|
2265
|
-
return
|
|
2411
|
+
return activeBridge.run(
|
|
2266
2412
|
{ [input.inputName]: { data: input.data, dims: input.dims } },
|
|
2267
2413
|
{ signal }
|
|
2268
2414
|
);
|
|
2269
2415
|
},
|
|
2270
|
-
dispose: () =>
|
|
2416
|
+
dispose: () => activeBridge.dispose()
|
|
2271
2417
|
};
|
|
2272
2418
|
}
|
|
2273
|
-
|
|
2419
|
+
const session = await createOrtSession(modelBytes, candidatePlan, {
|
|
2420
|
+
ort: options.ort?.module,
|
|
2421
|
+
wasmPaths: options.ort?.wasm?.paths,
|
|
2422
|
+
numThreads: options.ort?.wasm?.numThreads
|
|
2423
|
+
});
|
|
2424
|
+
runtimeVersion = session.runtimeVersion ?? null;
|
|
2274
2425
|
options.onProgress?.({ phase: "session", status: "complete" });
|
|
2426
|
+
return {
|
|
2427
|
+
run(input, signal) {
|
|
2428
|
+
return session.run(
|
|
2429
|
+
{ [input.inputName]: { data: input.data, dims: input.dims } },
|
|
2430
|
+
{ signal }
|
|
2431
|
+
);
|
|
2432
|
+
},
|
|
2433
|
+
dispose: () => session.dispose()
|
|
2434
|
+
};
|
|
2435
|
+
} catch (error) {
|
|
2436
|
+
try {
|
|
2437
|
+
await bridge?.dispose();
|
|
2438
|
+
} catch {
|
|
2439
|
+
}
|
|
2440
|
+
if (error instanceof PPDetectionError) throw error;
|
|
2441
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2442
|
+
throw new PPDetectionError(
|
|
2443
|
+
"SESSION_CREATE_FAILED",
|
|
2444
|
+
"\u521B\u5EFA ONNX Runtime \u4F1A\u8BDD\u5931\u8D25",
|
|
2445
|
+
{ phase: "create", causeMessage: message },
|
|
2446
|
+
{ cause: error }
|
|
2447
|
+
);
|
|
2448
|
+
} finally {
|
|
2449
|
+
sessionMs += now4() - sessionStartedAt;
|
|
2450
|
+
}
|
|
2451
|
+
};
|
|
2452
|
+
let selectedPlan = plan;
|
|
2453
|
+
let sessionMs = 0;
|
|
2454
|
+
let runtimeVersion = null;
|
|
2455
|
+
let selectedCandidateIndex = -1;
|
|
2456
|
+
for (const [candidateIndex, candidate] of plan.candidates.entries()) {
|
|
2457
|
+
const candidatePlan = {
|
|
2458
|
+
...plan,
|
|
2459
|
+
variantId: candidate.variantId,
|
|
2460
|
+
actualBackend: candidate.backend,
|
|
2461
|
+
actualPrecision: candidate.precision,
|
|
2462
|
+
executionMode: candidate.executionMode,
|
|
2463
|
+
candidates: [candidate]
|
|
2464
|
+
};
|
|
2465
|
+
try {
|
|
2466
|
+
executor = await createExecutorForPlan(candidatePlan);
|
|
2467
|
+
selectedPlan = candidatePlan;
|
|
2468
|
+
selectedCandidateIndex = candidateIndex;
|
|
2275
2469
|
break;
|
|
2276
2470
|
} catch (error) {
|
|
2277
2471
|
const mapped = error instanceof PPDetectionError ? error : new PPDetectionError("SESSION_CREATE_FAILED", String(error));
|
|
@@ -2281,11 +2475,6 @@ async function createPPDetection(options = {}) {
|
|
|
2281
2475
|
} catch {
|
|
2282
2476
|
}
|
|
2283
2477
|
executor = void 0;
|
|
2284
|
-
try {
|
|
2285
|
-
await activeBridge?.dispose();
|
|
2286
|
-
} catch {
|
|
2287
|
-
}
|
|
2288
|
-
activeBridge = void 0;
|
|
2289
2478
|
if (!hasNext) {
|
|
2290
2479
|
throw mapped;
|
|
2291
2480
|
}
|
|
@@ -2303,22 +2492,75 @@ async function createPPDetection(options = {}) {
|
|
|
2303
2492
|
}
|
|
2304
2493
|
}
|
|
2305
2494
|
if (!executor) throw new PPDetectionError("SESSION_CREATE_FAILED", "\u65E0\u6CD5\u521B\u5EFA\u68C0\u6D4B Session");
|
|
2306
|
-
const
|
|
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
|
+
},
|
|
2502
|
+
requestedBackend: options.backend ?? "auto",
|
|
2503
|
+
backend: selectedPlan.actualBackend,
|
|
2504
|
+
precision: selectedPlan.actualPrecision,
|
|
2505
|
+
mode: selectedPlan.executionMode,
|
|
2506
|
+
fallbacks,
|
|
2507
|
+
capabilities
|
|
2508
|
+
};
|
|
2509
|
+
let activeExecutor = executor;
|
|
2510
|
+
const fallbackExecutor = {
|
|
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;
|
|
2513
|
+
try {
|
|
2514
|
+
return await activeExecutor.run(attemptInput, signal);
|
|
2515
|
+
} catch (error) {
|
|
2516
|
+
if (options.allowFallback !== true || selectedCandidateIndex < 0 || selectedCandidateIndex >= plan.candidates.length - 1) {
|
|
2517
|
+
throw error;
|
|
2518
|
+
}
|
|
2519
|
+
const failedCandidate = plan.candidates[selectedCandidateIndex];
|
|
2520
|
+
const mapped = error instanceof PPDetectionError ? error : new PPDetectionError("INFERENCE_FAILED", String(error), {}, { cause: error });
|
|
2521
|
+
if (mapped.code === "ABORTED") throw mapped;
|
|
2522
|
+
const nextCandidate = plan.candidates[selectedCandidateIndex + 1];
|
|
2523
|
+
const nextPlan = {
|
|
2524
|
+
...plan,
|
|
2525
|
+
variantId: nextCandidate.variantId,
|
|
2526
|
+
actualBackend: nextCandidate.backend,
|
|
2527
|
+
actualPrecision: nextCandidate.precision,
|
|
2528
|
+
executionMode: nextCandidate.executionMode,
|
|
2529
|
+
candidates: [nextCandidate]
|
|
2530
|
+
};
|
|
2531
|
+
await activeExecutor.dispose();
|
|
2532
|
+
const nextExecutor = await createExecutorForPlan(nextPlan);
|
|
2533
|
+
activeExecutor = nextExecutor;
|
|
2534
|
+
selectedCandidateIndex += 1;
|
|
2535
|
+
selectedPlan = nextPlan;
|
|
2536
|
+
runtime.backend = nextPlan.actualBackend;
|
|
2537
|
+
runtime.precision = nextPlan.actualPrecision;
|
|
2538
|
+
runtime.mode = nextPlan.executionMode;
|
|
2539
|
+
runtime.runtimeVersion = runtimeVersion;
|
|
2540
|
+
const fallback = {
|
|
2541
|
+
cause: mapped.cause ?? mapped,
|
|
2542
|
+
code: mapped.code,
|
|
2543
|
+
message: mapped.message,
|
|
2544
|
+
precision: failedCandidate.precision,
|
|
2545
|
+
provider: failedCandidate.backend,
|
|
2546
|
+
stage: "inference",
|
|
2547
|
+
variantId: failedCandidate.variantId
|
|
2548
|
+
};
|
|
2549
|
+
fallbacks.push(fallback);
|
|
2550
|
+
options.onProgress?.({ phase: "fallback", status: "complete", fallback });
|
|
2551
|
+
return activeExecutor.run(input, signal);
|
|
2552
|
+
}
|
|
2553
|
+
},
|
|
2554
|
+
dispose: () => activeExecutor.dispose()
|
|
2555
|
+
};
|
|
2307
2556
|
loadTimings = { ...loadTimings, sessionMs, totalMs: now4() - loadStartedAt };
|
|
2308
2557
|
const detector = new PPDetectionDetectorImplementation({
|
|
2309
2558
|
capabilities,
|
|
2310
2559
|
manifest: runtimeManifest,
|
|
2311
2560
|
model: modelInfo(runtimeManifest, variant3.id, actualSource),
|
|
2312
|
-
runtime
|
|
2313
|
-
requestedBackend: options.backend ?? "auto",
|
|
2314
|
-
backend: selectedPlan.actualBackend,
|
|
2315
|
-
precision: selectedPlan.actualPrecision,
|
|
2316
|
-
mode: selectedPlan.executionMode,
|
|
2317
|
-
fallbacks,
|
|
2318
|
-
capabilities
|
|
2319
|
-
},
|
|
2561
|
+
runtime,
|
|
2320
2562
|
loadTimings,
|
|
2321
|
-
loadExecutor: () => Promise.resolve(
|
|
2563
|
+
loadExecutor: () => Promise.resolve(fallbackExecutor),
|
|
2322
2564
|
onProgress: options.onProgress,
|
|
2323
2565
|
clearCurrentModelCache: () => modelManager.clearCurrentModelCache(),
|
|
2324
2566
|
clearAllCache: () => modelManager.clearAllCache(),
|
|
@@ -2326,6 +2568,7 @@ async function createPPDetection(options = {}) {
|
|
|
2326
2568
|
disposeResources: () => modelManager.dispose()
|
|
2327
2569
|
});
|
|
2328
2570
|
await detector.load({ signal: options.signal });
|
|
2571
|
+
loadTimings.totalMs = now4() - loadStartedAt;
|
|
2329
2572
|
options.onProgress?.({ phase: "ready", status: "complete" });
|
|
2330
2573
|
return detector;
|
|
2331
2574
|
} catch (error) {
|
|
@@ -2333,10 +2576,6 @@ async function createPPDetection(options = {}) {
|
|
|
2333
2576
|
await executor?.dispose();
|
|
2334
2577
|
} catch {
|
|
2335
2578
|
}
|
|
2336
|
-
try {
|
|
2337
|
-
await activeBridge?.dispose();
|
|
2338
|
-
} catch {
|
|
2339
|
-
}
|
|
2340
2579
|
try {
|
|
2341
2580
|
await modelManager.dispose();
|
|
2342
2581
|
} catch {
|
|
@@ -2346,8 +2585,11 @@ async function createPPDetection(options = {}) {
|
|
|
2346
2585
|
}
|
|
2347
2586
|
async function clearModelCache() {
|
|
2348
2587
|
const manager = new ModelManager();
|
|
2349
|
-
|
|
2350
|
-
|
|
2588
|
+
try {
|
|
2589
|
+
await manager.clearAllCache();
|
|
2590
|
+
} finally {
|
|
2591
|
+
await manager.dispose();
|
|
2592
|
+
}
|
|
2351
2593
|
}
|
|
2352
2594
|
|
|
2353
2595
|
export { CURRENT_SDK_VERSION, IndexedDBModelCache, MemoryModelCache, ModelManager, PPDetectionError, adaptModelManifest, clearModelCache, createOrtSession, createPPDetection, loadModelAsset, parseDetectionManifest, parseModelManifest, probeCapabilities, probePPDetectionCapabilities, resolveModelAsset, selectExecutionPlan };
|