web-sdk-pp-detection 0.3.0 → 0.3.2
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 +19 -15
- package/dist/browser-global.js +255 -85
- package/dist/browser-global.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.js +255 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -138,9 +138,17 @@ interface PPDetectionProgressEvent {
|
|
|
138
138
|
readonly status: "start" | "progress" | "complete";
|
|
139
139
|
readonly loadedBytes?: number;
|
|
140
140
|
readonly totalBytes?: number;
|
|
141
|
+
readonly attempt?: number;
|
|
142
|
+
readonly maxAttempts?: number;
|
|
141
143
|
readonly fallback?: PPDetectionFallback;
|
|
142
144
|
}
|
|
145
|
+
interface ModelDownloadOptions {
|
|
146
|
+
readonly timeoutMs?: number;
|
|
147
|
+
readonly idleTimeoutMs?: number;
|
|
148
|
+
readonly maxRetries?: number;
|
|
149
|
+
}
|
|
143
150
|
interface CreatePPDetectionOptions {
|
|
151
|
+
readonly download?: ModelDownloadOptions;
|
|
144
152
|
readonly allowExperimental?: boolean;
|
|
145
153
|
readonly allowFallback?: boolean;
|
|
146
154
|
readonly backend?: BackendPreference;
|
|
@@ -518,10 +526,13 @@ type ModelFetcher = (input: RequestInfo | URL, init?: RequestInit) => Promise<Re
|
|
|
518
526
|
interface ModelDownloadProgress {
|
|
519
527
|
readonly loadedBytes: number;
|
|
520
528
|
readonly totalBytes?: number;
|
|
529
|
+
readonly attempt?: number;
|
|
530
|
+
readonly maxAttempts?: number;
|
|
521
531
|
}
|
|
522
532
|
interface LoadModelAssetOptions {
|
|
523
533
|
readonly fetcher?: ModelFetcher;
|
|
524
534
|
readonly signal?: AbortSignal;
|
|
535
|
+
readonly download?: ModelDownloadOptions;
|
|
525
536
|
readonly onProgress?: (progress: ModelDownloadProgress) => void;
|
|
526
537
|
}
|
|
527
538
|
interface ModelBytes {
|
|
@@ -549,6 +560,7 @@ interface ModelCache {
|
|
|
549
560
|
}
|
|
550
561
|
|
|
551
562
|
interface ModelManagerOptions {
|
|
563
|
+
readonly download?: ModelDownloadOptions;
|
|
552
564
|
readonly fetcher?: ModelFetcher;
|
|
553
565
|
readonly cache?: "memory" | "indexeddb" | false | ModelCache;
|
|
554
566
|
}
|
|
@@ -576,6 +588,7 @@ interface LoadedManagedModel {
|
|
|
576
588
|
}
|
|
577
589
|
declare class ModelManager {
|
|
578
590
|
private readonly fetcher?;
|
|
591
|
+
private readonly download;
|
|
579
592
|
private readonly cache;
|
|
580
593
|
private readonly coordinator;
|
|
581
594
|
private readonly lifecycle;
|
|
@@ -635,11 +648,11 @@ declare class IndexedDBModelCache implements ModelCache {
|
|
|
635
648
|
declare global {
|
|
636
649
|
var __PPDETECTION_SCRIPT_URL__: string | undefined;
|
|
637
650
|
}
|
|
638
|
-
declare const CURRENT_SDK_VERSION = "0.3.
|
|
651
|
+
declare const CURRENT_SDK_VERSION = "0.3.2";
|
|
639
652
|
|
|
640
653
|
declare function probePPDetectionCapabilities(options?: CapabilityProbeOptions): DetectionCapabilities;
|
|
641
654
|
|
|
642
655
|
declare function createPPDetection(options?: CreatePPDetectionOptions): Promise<PPDetectionDetectorImplementation>;
|
|
643
656
|
declare function clearModelCache(): Promise<void>;
|
|
644
657
|
|
|
645
|
-
export { type Backend, type BackendPreference, CURRENT_SDK_VERSION, type CacheEstimate, type CapabilityProbeOptions, type CreateOrtSessionOptions, type CreatePPDetectionOptions, type DecodedImage, type DetectOptions, type Detection, type DetectionBox, type DetectionCapabilities, type DetectionManifest, type DetectionModelVariant, type DetectionPoint, type DetectionPostprocessing, type DetectionPreprocessing, type DetectionTimings, type ExecutionCandidate, type ExecutionMode, type ExecutionPlan, type ImageRaster, type ImageSource, IndexedDBModelCache, type IndexedDBModelCacheOptions, type LoadManagedModelOptions, type LoadModelAssetOptions, type LoadedManagedModel, MemoryModelCache, type ModelBackend, type ModelBytes, type ModelCache, type ModelDownloadProgress, type ModelFetcher, type ModelInfo, ModelManager, type ModelManagerOptions, type ModelManifest, type ModelManifestMetadata, type ModelManifestSource, type ModelManifestVariant, type ModelPrecision, type ModelSource, type ModelSourceFailure, type ModelSourceKind, type ModelSourceSelection, type ModelVariant, type OrtModule, type OrtSessionHandle, type PPDetectionDetector, PPDetectionError, type PPDetectionErrorCode, type PPDetectionFallback, type PPDetectionLoadTimings, type PPDetectionModel, type PPDetectionModelInfo, type PPDetectionModelSourceInfo, type PPDetectionProgressEvent, type PPDetectionResult, type PPDetectionRuntimeInfo, type Precision, type ResolveModelAssetSelection, type ResolvedModelAsset, type RuntimeDetectionManifest, type RuntimeInfo, type SelectExecutionOptions, type TensorContract, type TimingBreakdown, type WorkerOrtOptions, type WorkerRequest, type WorkerResponse, adaptModelManifest, clearModelCache, createOrtSession, createPPDetection, loadModelAsset, parseDetectionManifest, parseModelManifest, probeCapabilities, probePPDetectionCapabilities, resolveModelAsset, selectExecutionPlan };
|
|
658
|
+
export { type Backend, type BackendPreference, CURRENT_SDK_VERSION, type CacheEstimate, type CapabilityProbeOptions, type CreateOrtSessionOptions, type CreatePPDetectionOptions, type DecodedImage, type DetectOptions, type Detection, type DetectionBox, type DetectionCapabilities, type DetectionManifest, type DetectionModelVariant, type DetectionPoint, type DetectionPostprocessing, type DetectionPreprocessing, type DetectionTimings, type ExecutionCandidate, type ExecutionMode, type ExecutionPlan, type ImageRaster, type ImageSource, IndexedDBModelCache, type IndexedDBModelCacheOptions, type LoadManagedModelOptions, type LoadModelAssetOptions, type LoadedManagedModel, MemoryModelCache, type ModelBackend, type ModelBytes, type ModelCache, type ModelDownloadOptions, type ModelDownloadProgress, type ModelFetcher, type ModelInfo, ModelManager, type ModelManagerOptions, type ModelManifest, type ModelManifestMetadata, type ModelManifestSource, type ModelManifestVariant, type ModelPrecision, type ModelSource, type ModelSourceFailure, type ModelSourceKind, type ModelSourceSelection, type ModelVariant, type OrtModule, type OrtSessionHandle, type PPDetectionDetector, PPDetectionError, type PPDetectionErrorCode, type PPDetectionFallback, type PPDetectionLoadTimings, type PPDetectionModel, type PPDetectionModelInfo, type PPDetectionModelSourceInfo, type PPDetectionProgressEvent, type PPDetectionResult, type PPDetectionRuntimeInfo, type Precision, type ResolveModelAssetSelection, type ResolvedModelAsset, type RuntimeDetectionManifest, type RuntimeInfo, type SelectExecutionOptions, type TensorContract, type TimingBreakdown, type WorkerOrtOptions, type WorkerRequest, type WorkerResponse, adaptModelManifest, clearModelCache, createOrtSession, createPPDetection, loadModelAsset, parseDetectionManifest, parseModelManifest, probeCapabilities, probePPDetectionCapabilities, resolveModelAsset, selectExecutionPlan };
|
package/dist/index.js
CHANGED
|
@@ -371,34 +371,58 @@ function clipBicubic(value) {
|
|
|
371
371
|
const rounded = value >> BICUBIC_PRECISION_BITS;
|
|
372
372
|
return Math.max(0, Math.min(255, rounded));
|
|
373
373
|
}
|
|
374
|
-
function
|
|
374
|
+
function writeBicubicChannels(raster, resizedWidth, resizedHeight, target) {
|
|
375
375
|
const horizontal = createBicubicAxis(raster.width, resizedWidth);
|
|
376
376
|
const vertical = createBicubicAxis(raster.height, resizedHeight);
|
|
377
|
-
const
|
|
377
|
+
const rowStride = resizedWidth * 3;
|
|
378
|
+
const intermediate = new Uint8Array(raster.height * rowStride);
|
|
378
379
|
for (let y = 0; y < raster.height; y += 1) {
|
|
380
|
+
const sourceRow = y * raster.width * 4;
|
|
381
|
+
const targetRow = y * rowStride;
|
|
379
382
|
for (let x = 0; x < resizedWidth; x += 1) {
|
|
380
383
|
const [start, count] = horizontal.bounds[x];
|
|
381
384
|
const coefficients = horizontal.coefficients[x];
|
|
382
|
-
let
|
|
385
|
+
let red = BICUBIC_ROUNDING;
|
|
386
|
+
let green = BICUBIC_ROUNDING;
|
|
387
|
+
let blue = BICUBIC_ROUNDING;
|
|
388
|
+
let source2 = sourceRow + start * 4;
|
|
383
389
|
for (let index = 0; index < count; index += 1) {
|
|
384
|
-
|
|
390
|
+
const coefficient = coefficients[index];
|
|
391
|
+
red += raster.rgba[source2] * coefficient;
|
|
392
|
+
green += raster.rgba[source2 + 1] * coefficient;
|
|
393
|
+
blue += raster.rgba[source2 + 2] * coefficient;
|
|
394
|
+
source2 += 4;
|
|
385
395
|
}
|
|
386
|
-
|
|
396
|
+
const offset = targetRow + x * 3;
|
|
397
|
+
intermediate[offset] = clipBicubic(red);
|
|
398
|
+
intermediate[offset + 1] = clipBicubic(green);
|
|
399
|
+
intermediate[offset + 2] = clipBicubic(blue);
|
|
387
400
|
}
|
|
388
401
|
}
|
|
389
|
-
const
|
|
402
|
+
const plane = target.inputWidth * target.inputHeight;
|
|
390
403
|
for (let y = 0; y < resizedHeight; y += 1) {
|
|
391
404
|
const [start, count] = vertical.bounds[y];
|
|
392
405
|
const coefficients = vertical.coefficients[y];
|
|
406
|
+
const sourceRow = start * rowStride;
|
|
407
|
+
const targetRow = (y + target.padTop) * target.inputWidth + target.padLeft;
|
|
393
408
|
for (let x = 0; x < resizedWidth; x += 1) {
|
|
394
|
-
let
|
|
409
|
+
let red = BICUBIC_ROUNDING;
|
|
410
|
+
let green = BICUBIC_ROUNDING;
|
|
411
|
+
let blue = BICUBIC_ROUNDING;
|
|
412
|
+
let source2 = sourceRow + x * 3;
|
|
395
413
|
for (let index = 0; index < count; index += 1) {
|
|
396
|
-
|
|
414
|
+
const coefficient = coefficients[index];
|
|
415
|
+
red += intermediate[source2] * coefficient;
|
|
416
|
+
green += intermediate[source2 + 1] * coefficient;
|
|
417
|
+
blue += intermediate[source2 + 2] * coefficient;
|
|
418
|
+
source2 += rowStride;
|
|
397
419
|
}
|
|
398
|
-
|
|
420
|
+
const offset = targetRow + x;
|
|
421
|
+
target.data[offset] = target.values[clipBicubic(red)];
|
|
422
|
+
target.data[plane + offset] = target.values[256 + clipBicubic(green)];
|
|
423
|
+
target.data[plane * 2 + offset] = target.values[512 + clipBicubic(blue)];
|
|
399
424
|
}
|
|
400
425
|
}
|
|
401
|
-
return output;
|
|
402
426
|
}
|
|
403
427
|
function preprocessImage(raster, preprocessing) {
|
|
404
428
|
const inputWidth = preprocessing.size.width;
|
|
@@ -425,18 +449,35 @@ function preprocessImage(raster, preprocessing) {
|
|
|
425
449
|
const mean = normalize ? preprocessing.mean ?? [0, 0, 0] : [0, 0, 0];
|
|
426
450
|
const std = normalize ? preprocessing.std ?? [1, 1, 1] : [1, 1, 1];
|
|
427
451
|
const interpolation2 = preprocessing.interpolation ?? "bilinear";
|
|
452
|
+
const bicubicValues = doResize && interpolation2 === "bicubic" ? new Float32Array(256 * 3) : void 0;
|
|
428
453
|
for (let channel = 0; channel < 3; channel += 1) {
|
|
429
454
|
const padding = normalize && mean[channel] !== 0 ? -mean[channel] / std[channel] : 0;
|
|
430
455
|
data.fill(padding, channel * plane, (channel + 1) * plane);
|
|
431
|
-
|
|
456
|
+
if (bicubicValues) {
|
|
457
|
+
for (let pixel = 0; pixel < 256; pixel += 1) {
|
|
458
|
+
const scaled = rescale ? pixel * preprocessing.rescaleFactor : pixel;
|
|
459
|
+
bicubicValues[channel * 256 + pixel] = normalize ? (scaled - mean[channel]) / std[channel] : scaled;
|
|
460
|
+
}
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
432
463
|
for (let y = 0; y < resizedHeight; y += 1) {
|
|
433
464
|
for (let x = 0; x < resizedWidth; x += 1) {
|
|
434
|
-
const pixel =
|
|
465
|
+
const pixel = doResize ? bilinearChannel(raster, x, y, resizedWidth, resizedHeight, channel) : sampleChannel(raster, x, y, channel);
|
|
435
466
|
const scaled = rescale ? pixel * preprocessing.rescaleFactor : pixel;
|
|
436
467
|
data[channel * plane + (y + padTop) * inputWidth + x + padLeft] = normalize ? (scaled - mean[channel]) / std[channel] : scaled;
|
|
437
468
|
}
|
|
438
469
|
}
|
|
439
470
|
}
|
|
471
|
+
if (bicubicValues) {
|
|
472
|
+
writeBicubicChannels(raster, resizedWidth, resizedHeight, {
|
|
473
|
+
data,
|
|
474
|
+
inputWidth,
|
|
475
|
+
inputHeight,
|
|
476
|
+
padLeft,
|
|
477
|
+
padTop,
|
|
478
|
+
values: bicubicValues
|
|
479
|
+
});
|
|
480
|
+
}
|
|
440
481
|
return {
|
|
441
482
|
data,
|
|
442
483
|
dims: [1, 3, inputHeight, inputWidth],
|
|
@@ -1433,11 +1474,36 @@ async function verifyModelIntegrity(bytes, expected, signal) {
|
|
|
1433
1474
|
}
|
|
1434
1475
|
|
|
1435
1476
|
// src/model/download.ts
|
|
1477
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
1478
|
+
var RetryableDownloadError = class extends PPDetectionError {
|
|
1479
|
+
constructor(message, details = {}, cause) {
|
|
1480
|
+
super("MODEL_DOWNLOAD_FAILED", message, details, { cause });
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
function resolveDownloadOptions(options = {}) {
|
|
1484
|
+
if (options === null || typeof options !== "object")
|
|
1485
|
+
throw new PPDetectionError("INVALID_INPUT", "\u4E0B\u8F7D\u914D\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
1486
|
+
const resolved = {
|
|
1487
|
+
timeoutMs: options.timeoutMs === void 0 ? 18e4 : options.timeoutMs,
|
|
1488
|
+
idleTimeoutMs: options.idleTimeoutMs === void 0 ? 3e4 : options.idleTimeoutMs,
|
|
1489
|
+
maxRetries: options.maxRetries === void 0 ? 2 : options.maxRetries
|
|
1490
|
+
};
|
|
1491
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
1492
|
+
const maximum = key === "maxRetries" ? 5 : 2147483647;
|
|
1493
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > maximum)
|
|
1494
|
+
throw new PPDetectionError("INVALID_INPUT", "\u4E0B\u8F7D\u53C2\u6570\u5FC5\u987B\u4E3A\u5141\u8BB8\u8303\u56F4\u5185\u7684\u5B89\u5168\u6574\u6570", {
|
|
1495
|
+
parameter: key,
|
|
1496
|
+
value,
|
|
1497
|
+
maximum
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
return resolved;
|
|
1501
|
+
}
|
|
1436
1502
|
function now() {
|
|
1437
1503
|
return globalThis.performance?.now() ?? Date.now();
|
|
1438
1504
|
}
|
|
1439
1505
|
function aborted(error, signal) {
|
|
1440
|
-
return signal?.aborted === true || error instanceof
|
|
1506
|
+
return signal?.aborted === true || error instanceof Error && error.name === "AbortError";
|
|
1441
1507
|
}
|
|
1442
1508
|
function throwIfAborted3(signal) {
|
|
1443
1509
|
if (signal?.aborted) throw new PPDetectionError("ABORTED", "\u6A21\u578B\u4E0B\u8F7D\u5DF2\u53D6\u6D88");
|
|
@@ -1465,106 +1531,206 @@ function validatePartialResponse(response, expectedBytes) {
|
|
|
1465
1531
|
});
|
|
1466
1532
|
}
|
|
1467
1533
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
throwIfAborted3(signal);
|
|
1473
|
-
onProgress?.({ loadedBytes: bytes2.byteLength, totalBytes });
|
|
1474
|
-
return bytes2;
|
|
1534
|
+
function cancelQuietly(cancel) {
|
|
1535
|
+
try {
|
|
1536
|
+
void Promise.resolve(cancel()).catch(() => void 0);
|
|
1537
|
+
} catch {
|
|
1475
1538
|
}
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1539
|
+
}
|
|
1540
|
+
async function downloadAttempt(asset, fetcher, options, policy, attempt) {
|
|
1541
|
+
const controller = new AbortController();
|
|
1542
|
+
let response;
|
|
1543
|
+
let reader;
|
|
1544
|
+
let active = true;
|
|
1545
|
+
let cancelledBody = false;
|
|
1546
|
+
let stopError;
|
|
1547
|
+
let totalTimer;
|
|
1548
|
+
let idleTimer;
|
|
1549
|
+
let rejectStop;
|
|
1550
|
+
const stopped = new Promise((_resolve, reject) => {
|
|
1551
|
+
rejectStop = reject;
|
|
1552
|
+
});
|
|
1553
|
+
void stopped.catch(() => void 0);
|
|
1554
|
+
const cancelBody = (reason) => {
|
|
1555
|
+
if (cancelledBody || !reader && !response?.body) return;
|
|
1556
|
+
cancelledBody = true;
|
|
1557
|
+
if (reader) cancelQuietly(() => reader.cancel(reason));
|
|
1558
|
+
else cancelQuietly(() => response.body.cancel(reason));
|
|
1559
|
+
};
|
|
1560
|
+
const stop = (error) => {
|
|
1561
|
+
if (!active || stopError) return;
|
|
1562
|
+
stopError = error;
|
|
1563
|
+
rejectStop(error);
|
|
1564
|
+
controller.abort();
|
|
1565
|
+
cancelBody(error);
|
|
1566
|
+
};
|
|
1567
|
+
const abort = () => stop(new PPDetectionError("ABORTED", "\u6A21\u578B\u4E0B\u8F7D\u5DF2\u53D6\u6D88"));
|
|
1568
|
+
const renewIdle = () => {
|
|
1569
|
+
clearTimeout(idleTimer);
|
|
1570
|
+
if (policy.idleTimeoutMs > 0)
|
|
1571
|
+
idleTimer = setTimeout(
|
|
1572
|
+
() => stop(
|
|
1573
|
+
new RetryableDownloadError("\u6A21\u578B\u4E0B\u8F7D\u957F\u65F6\u95F4\u6CA1\u6709\u65B0\u589E\u5B57\u8282", {
|
|
1574
|
+
idleTimeoutMs: policy.idleTimeoutMs
|
|
1575
|
+
})
|
|
1576
|
+
),
|
|
1577
|
+
policy.idleTimeoutMs
|
|
1578
|
+
);
|
|
1579
|
+
};
|
|
1580
|
+
const checkActive = () => {
|
|
1581
|
+
if (stopError) throw stopError;
|
|
1582
|
+
throwIfAborted3(options.signal);
|
|
1583
|
+
};
|
|
1584
|
+
const network = async (operation) => {
|
|
1585
|
+
try {
|
|
1586
|
+
checkActive();
|
|
1587
|
+
const value = await Promise.race([operation(), stopped]);
|
|
1588
|
+
checkActive();
|
|
1589
|
+
return value;
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
if (stopError) throw stopError;
|
|
1592
|
+
if (aborted(error, options.signal))
|
|
1593
|
+
throw new PPDetectionError("ABORTED", "\u6A21\u578B\u4E0B\u8F7D\u5DF2\u53D6\u6D88", {}, { cause: error });
|
|
1594
|
+
if (error instanceof PPDetectionError) throw error;
|
|
1595
|
+
throw new RetryableDownloadError(
|
|
1596
|
+
"\u6A21\u578B\u4E0B\u8F7D\u8BF7\u6C42\u6216\u54CD\u5E94\u8BFB\u53D6\u5931\u8D25",
|
|
1597
|
+
{ sourceKind: asset.source.kind, downloadUrl: asset.source.downloadUrl },
|
|
1598
|
+
error
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
const report = (loadedBytes) => {
|
|
1603
|
+
checkActive();
|
|
1604
|
+
options.onProgress?.({
|
|
1605
|
+
loadedBytes,
|
|
1606
|
+
totalBytes: asset.source.bytes,
|
|
1607
|
+
attempt,
|
|
1608
|
+
maxAttempts: policy.maxRetries + 1
|
|
1609
|
+
});
|
|
1610
|
+
checkActive();
|
|
1611
|
+
};
|
|
1612
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
1479
1613
|
try {
|
|
1614
|
+
throwIfAborted3(options.signal);
|
|
1615
|
+
if (policy.timeoutMs > 0)
|
|
1616
|
+
totalTimer = setTimeout(
|
|
1617
|
+
() => stop(
|
|
1618
|
+
new RetryableDownloadError("\u6A21\u578B\u4E0B\u8F7D\u8D85\u8FC7\u8BF7\u6C42\u603B\u65F6\u9650", { timeoutMs: policy.timeoutMs })
|
|
1619
|
+
),
|
|
1620
|
+
policy.timeoutMs
|
|
1621
|
+
);
|
|
1622
|
+
renewIdle();
|
|
1623
|
+
report(0);
|
|
1624
|
+
response = await network(
|
|
1625
|
+
() => Promise.resolve(
|
|
1626
|
+
fetcher(asset.source.downloadUrl, {
|
|
1627
|
+
signal: controller.signal,
|
|
1628
|
+
...attempt > 1 ? { cache: "reload" } : {}
|
|
1629
|
+
})
|
|
1630
|
+
).then((value) => {
|
|
1631
|
+
response = value;
|
|
1632
|
+
if (!active || stopError) cancelBody(stopError);
|
|
1633
|
+
return value;
|
|
1634
|
+
})
|
|
1635
|
+
);
|
|
1636
|
+
if (!response.ok) {
|
|
1637
|
+
const details = {
|
|
1638
|
+
sourceKind: asset.source.kind,
|
|
1639
|
+
status: response.status,
|
|
1640
|
+
statusText: response.statusText
|
|
1641
|
+
};
|
|
1642
|
+
if (RETRYABLE_STATUSES.has(response.status))
|
|
1643
|
+
throw new RetryableDownloadError("\u6A21\u578B\u4E0B\u8F7D\u8FD4\u56DE\u53EF\u91CD\u8BD5\u72B6\u6001", details);
|
|
1644
|
+
throw new PPDetectionError("MODEL_DOWNLOAD_FAILED", "\u6A21\u578B\u4E0B\u8F7D\u8FD4\u56DE\u975E\u6210\u529F\u72B6\u6001", details);
|
|
1645
|
+
}
|
|
1646
|
+
validatePartialResponse(response, asset.source.bytes);
|
|
1647
|
+
contentLength(response, asset.source.bytes);
|
|
1648
|
+
if (!response.body) {
|
|
1649
|
+
const bytes2 = await network(() => response.arrayBuffer());
|
|
1650
|
+
report(bytes2.byteLength);
|
|
1651
|
+
return bytes2;
|
|
1652
|
+
}
|
|
1653
|
+
reader = response.body.getReader();
|
|
1654
|
+
const chunks = [];
|
|
1655
|
+
let loadedBytes = 0;
|
|
1480
1656
|
while (true) {
|
|
1481
|
-
|
|
1482
|
-
const chunk = await reader.read();
|
|
1657
|
+
const chunk = await network(() => reader.read());
|
|
1483
1658
|
if (chunk.done) break;
|
|
1659
|
+
if (chunk.value.byteLength === 0) continue;
|
|
1484
1660
|
loadedBytes += chunk.value.byteLength;
|
|
1485
|
-
if (loadedBytes >
|
|
1661
|
+
if (loadedBytes > asset.source.bytes)
|
|
1486
1662
|
throw new PPDetectionError("MODEL_INTEGRITY_FAILED", "\u6A21\u578B\u54CD\u5E94\u8D85\u8FC7\u6E05\u5355\u58F0\u660E\u5927\u5C0F", {
|
|
1487
|
-
expectedBytes,
|
|
1663
|
+
expectedBytes: asset.source.bytes,
|
|
1488
1664
|
loadedBytes
|
|
1489
1665
|
});
|
|
1490
|
-
}
|
|
1491
1666
|
chunks.push(chunk.value);
|
|
1492
|
-
|
|
1667
|
+
renewIdle();
|
|
1668
|
+
report(loadedBytes);
|
|
1493
1669
|
}
|
|
1670
|
+
const bytes = new Uint8Array(loadedBytes);
|
|
1671
|
+
let offset = 0;
|
|
1672
|
+
for (const chunk of chunks) {
|
|
1673
|
+
bytes.set(chunk, offset);
|
|
1674
|
+
offset += chunk.byteLength;
|
|
1675
|
+
}
|
|
1676
|
+
report(loadedBytes);
|
|
1677
|
+
return bytes.buffer;
|
|
1494
1678
|
} catch (error) {
|
|
1679
|
+
controller.abort();
|
|
1680
|
+
cancelBody(error);
|
|
1681
|
+
throw error;
|
|
1682
|
+
} finally {
|
|
1683
|
+
active = false;
|
|
1684
|
+
clearTimeout(totalTimer);
|
|
1685
|
+
clearTimeout(idleTimer);
|
|
1686
|
+
options.signal?.removeEventListener("abort", abort);
|
|
1495
1687
|
try {
|
|
1496
|
-
|
|
1688
|
+
reader?.releaseLock();
|
|
1497
1689
|
} catch {
|
|
1498
1690
|
}
|
|
1499
|
-
throw error;
|
|
1500
|
-
} finally {
|
|
1501
|
-
reader.releaseLock();
|
|
1502
1691
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1692
|
+
}
|
|
1693
|
+
function waitForRetry(delayMs, signal) {
|
|
1694
|
+
throwIfAborted3(signal);
|
|
1695
|
+
return new Promise((resolve, reject) => {
|
|
1696
|
+
const abort = () => {
|
|
1697
|
+
clearTimeout(timer);
|
|
1698
|
+
signal?.removeEventListener("abort", abort);
|
|
1699
|
+
reject(new PPDetectionError("ABORTED", "\u6A21\u578B\u4E0B\u8F7D\u5DF2\u53D6\u6D88"));
|
|
1700
|
+
};
|
|
1701
|
+
const timer = setTimeout(() => {
|
|
1702
|
+
signal?.removeEventListener("abort", abort);
|
|
1703
|
+
resolve();
|
|
1704
|
+
}, delayMs);
|
|
1705
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
1706
|
+
if (signal?.aborted) abort();
|
|
1707
|
+
});
|
|
1511
1708
|
}
|
|
1512
1709
|
async function loadModelAsset(asset, options = {}) {
|
|
1513
1710
|
throwIfAborted3(options.signal);
|
|
1711
|
+
const policy = resolveDownloadOptions(options.download);
|
|
1514
1712
|
const fetcher = options.fetcher ?? globalThis.fetch?.bind(globalThis);
|
|
1515
1713
|
if (!fetcher)
|
|
1516
1714
|
throw new PPDetectionError("MODEL_DOWNLOAD_FAILED", "\u5F53\u524D\u73AF\u5883\u6CA1\u6709 fetch API", {
|
|
1517
1715
|
sourceKind: asset.source.kind
|
|
1518
1716
|
});
|
|
1519
1717
|
const downloadStarted = now();
|
|
1520
|
-
let response;
|
|
1521
|
-
try {
|
|
1522
|
-
response = await fetcher(asset.source.downloadUrl, { signal: options.signal });
|
|
1523
|
-
} catch (error) {
|
|
1524
|
-
if (aborted(error, options.signal))
|
|
1525
|
-
throw new PPDetectionError("ABORTED", "\u6A21\u578B\u4E0B\u8F7D\u5DF2\u53D6\u6D88", {}, { cause: error });
|
|
1526
|
-
throw new PPDetectionError(
|
|
1527
|
-
"MODEL_DOWNLOAD_FAILED",
|
|
1528
|
-
"\u6A21\u578B\u4E0B\u8F7D\u8BF7\u6C42\u5931\u8D25",
|
|
1529
|
-
{
|
|
1530
|
-
sourceKind: asset.source.kind,
|
|
1531
|
-
downloadUrl: asset.source.downloadUrl
|
|
1532
|
-
},
|
|
1533
|
-
{ cause: error }
|
|
1534
|
-
);
|
|
1535
|
-
}
|
|
1536
|
-
if (!response.ok) {
|
|
1537
|
-
throw new PPDetectionError("MODEL_DOWNLOAD_FAILED", "\u6A21\u578B\u4E0B\u8F7D\u8FD4\u56DE\u975E\u6210\u529F\u72B6\u6001", {
|
|
1538
|
-
sourceKind: asset.source.kind,
|
|
1539
|
-
status: response.status,
|
|
1540
|
-
statusText: response.statusText
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
validatePartialResponse(response, asset.source.bytes);
|
|
1544
1718
|
let bytes;
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
{ cause: error }
|
|
1556
|
-
);
|
|
1719
|
+
for (let attempt = 1; ; attempt++) {
|
|
1720
|
+
throwIfAborted3(options.signal);
|
|
1721
|
+
try {
|
|
1722
|
+
bytes = await downloadAttempt(asset, fetcher, options, policy, attempt);
|
|
1723
|
+
break;
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
throwIfAborted3(options.signal);
|
|
1726
|
+
if (!(error instanceof RetryableDownloadError) || attempt > policy.maxRetries) throw error;
|
|
1727
|
+
await waitForRetry(Math.min(500 * 2 ** (attempt - 1), 4e3), options.signal);
|
|
1728
|
+
}
|
|
1557
1729
|
}
|
|
1558
1730
|
const modelDownloadMs = now() - downloadStarted;
|
|
1559
1731
|
const integrityStarted = now();
|
|
1560
1732
|
await verifyModelIntegrity(bytes, asset.source, options.signal);
|
|
1561
|
-
return {
|
|
1562
|
-
bytes,
|
|
1563
|
-
timings: {
|
|
1564
|
-
modelDownloadMs,
|
|
1565
|
-
integrityMs: now() - integrityStarted
|
|
1566
|
-
}
|
|
1567
|
-
};
|
|
1733
|
+
return { bytes, timings: { modelDownloadMs, integrityMs: now() - integrityStarted } };
|
|
1568
1734
|
}
|
|
1569
1735
|
|
|
1570
1736
|
// src/model/source-resolver.ts
|
|
@@ -1631,6 +1797,7 @@ function throwIfAborted4(signal) {
|
|
|
1631
1797
|
}
|
|
1632
1798
|
var ModelManager = class {
|
|
1633
1799
|
fetcher;
|
|
1800
|
+
download;
|
|
1634
1801
|
cache;
|
|
1635
1802
|
coordinator;
|
|
1636
1803
|
lifecycle = new AbortController();
|
|
@@ -1639,6 +1806,7 @@ var ModelManager = class {
|
|
|
1639
1806
|
disposed = false;
|
|
1640
1807
|
disposePromise;
|
|
1641
1808
|
constructor(options = {}) {
|
|
1809
|
+
this.download = resolveDownloadOptions(options.download);
|
|
1642
1810
|
this.fetcher = options.fetcher;
|
|
1643
1811
|
this.cache = createCache(options.cache);
|
|
1644
1812
|
this.coordinator = coordinateCache(this.cache);
|
|
@@ -1735,6 +1903,7 @@ var ModelManager = class {
|
|
|
1735
1903
|
try {
|
|
1736
1904
|
loaded = await loadModelAsset(asset, {
|
|
1737
1905
|
fetcher: this.fetcher,
|
|
1906
|
+
download: this.download,
|
|
1738
1907
|
signal: options.signal,
|
|
1739
1908
|
onProgress: options.onProgress
|
|
1740
1909
|
});
|
|
@@ -2219,7 +2388,7 @@ var WorkerBridge = class {
|
|
|
2219
2388
|
};
|
|
2220
2389
|
|
|
2221
2390
|
// src/index.ts
|
|
2222
|
-
var CURRENT_SDK_VERSION = "0.3.
|
|
2391
|
+
var CURRENT_SDK_VERSION = "0.3.2";
|
|
2223
2392
|
function probePPDetectionCapabilities(options = {}) {
|
|
2224
2393
|
return probeCapabilities(options);
|
|
2225
2394
|
}
|
|
@@ -2344,6 +2513,7 @@ async function createPPDetection(options = {}) {
|
|
|
2344
2513
|
simpleManifest(runtimeManifest)
|
|
2345
2514
|
);
|
|
2346
2515
|
const modelManager = new ModelManager({
|
|
2516
|
+
download: options.download,
|
|
2347
2517
|
cache: options.cache === false ? false : options.cache === "memory" ? "memory" : void 0
|
|
2348
2518
|
});
|
|
2349
2519
|
let executor;
|