@sssxyd/face-liveness-detector 0.2.22 → 0.2.23

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/index.esm.js CHANGED
@@ -351,16 +351,16 @@ async function preloadOpenCV(timeout = 30000) {
351
351
  */
352
352
  async function _initializeOpenCV(timeout) {
353
353
  const initStartTime = performance.now();
354
- console.log('[FaceDetectionEngine] Waiting for OpenCV WASM initialization...');
354
+ console.log('Waiting for OpenCV WASM initialization...');
355
355
  // 快速路径:检查是否已经初始化
356
356
  if (cvModule.Mat) {
357
357
  const initTime = performance.now() - initStartTime;
358
- console.log(`[FaceDetectionEngine] OpenCV.js already initialized, took ${initTime.toFixed(2)}ms`);
358
+ console.log(`OpenCV.js already initialized, took ${initTime.toFixed(2)}ms`);
359
359
  return cvModule;
360
360
  }
361
361
  if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
362
362
  const initTime = performance.now() - initStartTime;
363
- console.log(`[FaceDetectionEngine] OpenCV.js already initialized (from global), took ${initTime.toFixed(2)}ms`);
363
+ console.log(`OpenCV.js already initialized (from global), took ${initTime.toFixed(2)}ms`);
364
364
  cvModule = globalThis.cv;
365
365
  return cvModule;
366
366
  }
@@ -368,10 +368,10 @@ async function _initializeOpenCV(timeout) {
368
368
  if (typeof globalThis !== 'undefined' && !globalThis.cv) {
369
369
  if (cvModule && Object.isExtensible(cvModule)) {
370
370
  globalThis.cv = cvModule;
371
- console.log('[FaceDetectionEngine] cvModule assigned to globalThis.cv');
371
+ console.log('cvModule assigned to globalThis.cv');
372
372
  }
373
373
  else {
374
- console.log('[FaceDetectionEngine] cvModule is not extensible or globalThis already has cv');
374
+ console.log('cvModule is not extensible or globalThis already has cv');
375
375
  }
376
376
  }
377
377
  return new Promise((resolve, reject) => {
@@ -380,7 +380,7 @@ async function _initializeOpenCV(timeout) {
380
380
  // 防止多次调用 resolve/reject
381
381
  let finished = false;
382
382
  const timeoutId = setTimeout(() => {
383
- console.error('[FaceDetectionEngine] OpenCV.js initialization timeout after ' + timeout + 'ms');
383
+ console.error('OpenCV.js initialization timeout after ' + timeout + 'ms');
384
384
  finished = true;
385
385
  if (pollInterval) {
386
386
  clearInterval(pollInterval);
@@ -389,65 +389,65 @@ async function _initializeOpenCV(timeout) {
389
389
  }, timeout);
390
390
  const resolveOnce = (source) => {
391
391
  if (finished) {
392
- console.log('[FaceDetectionEngine] [resolveOnce] Already finished, ignoring call from:', source);
392
+ console.log('[resolveOnce] Already finished, ignoring call from:', source);
393
393
  return;
394
394
  }
395
395
  finished = true;
396
- console.log('[FaceDetectionEngine] [resolveOnce] Marking as finished');
396
+ console.log('[resolveOnce] Marking as finished');
397
397
  // 立即停止所有定时器和轮询
398
398
  clearTimeout(timeoutId);
399
399
  if (pollInterval !== null) {
400
400
  clearInterval(pollInterval);
401
401
  pollInterval = null;
402
- console.log('[FaceDetectionEngine] [resolveOnce] Poll interval cleared');
402
+ console.log('[resolveOnce] Poll interval cleared');
403
403
  }
404
404
  const initTime = performance.now() - initStartTime;
405
- console.log(`[FaceDetectionEngine] OpenCV.js initialized (${source}), took ${initTime.toFixed(2)}ms`);
405
+ console.log(`OpenCV.js initialized (${source}), took ${initTime.toFixed(2)}ms`);
406
406
  // 标记初始化完成
407
407
  opencvInitialized = true;
408
408
  // 返回简单的标记,实际的 cv 对象已经在 globalThis.cv 上了
409
409
  // 通过 getCvSync() 获取
410
410
  resolve(initTime);
411
- console.log('[FaceDetectionEngine] [resolveOnce] Promise resolved with true');
411
+ console.log('[resolveOnce] Promise resolved');
412
412
  };
413
413
  // 尝试设置回调(只有在 cvModule 可扩展时才尝试)
414
414
  const canSetCallback = cvModule && Object.isExtensible(cvModule);
415
415
  if (canSetCallback) {
416
416
  try {
417
417
  const originalOnRuntimeInitialized = cvModule.onRuntimeInitialized(cvModule).onRuntimeInitialized = () => {
418
- console.log('[FaceDetectionEngine] onRuntimeInitialized callback triggered');
418
+ console.log('[onRuntimeInitialized] callback triggered');
419
419
  // 调用原始回调(如果存在)
420
420
  if (originalOnRuntimeInitialized && typeof originalOnRuntimeInitialized === 'function') {
421
421
  try {
422
422
  originalOnRuntimeInitialized();
423
423
  }
424
424
  catch (e) {
425
- console.warn('[FaceDetectionEngine] Original onRuntimeInitialized callback failed:', e);
425
+ console.warn('[onRuntimeInitialized] callback failed:', e);
426
426
  }
427
427
  }
428
428
  resolveOnce('callback');
429
429
  };
430
- console.log('[FaceDetectionEngine] onRuntimeInitialized callback set successfully');
430
+ console.log('[onRuntimeInitialized] callback set successfully');
431
431
  }
432
432
  catch (e) {
433
- console.warn('[FaceDetectionEngine] Failed to set onRuntimeInitialized callback, will use polling:', e);
433
+ console.warn('[onRuntimeInitialized] Failed to set callback, will use polling:', e);
434
434
  }
435
435
  }
436
436
  else {
437
- console.log('[FaceDetectionEngine] cvModule is not extensible, using polling mode');
437
+ console.log('[polling] cvModule is not extensible, using polling mode');
438
438
  }
439
439
  // 启动轮询作为备用方案或主要方案
440
440
  pollInterval = setInterval(() => {
441
- console.log('[FaceDetectionEngine] [polling] Checking for Mat class...');
441
+ console.log('[polling] Checking for Mat class...');
442
442
  // 优先检查 cvModule 中是否有 Mat
443
443
  if (cvModule.Mat) {
444
- console.log('[FaceDetectionEngine] [polling] Found Mat in cvModule');
444
+ console.log('[polling] Found Mat in cvModule');
445
445
  resolveOnce('cvModule polling');
446
446
  return;
447
447
  }
448
448
  // 其次检查 globalThis.cv 中是否有 Mat
449
449
  if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
450
- console.log('[FaceDetectionEngine] [polling] Found Mat in globalThis.cv');
450
+ console.log('[polling] Found Mat in globalThis.cv');
451
451
  cvModule = globalThis.cv;
452
452
  resolveOnce('globalThis.cv polling');
453
453
  return;
@@ -461,38 +461,39 @@ async function _initializeOpenCV(timeout) {
461
461
  * @returns Promise that resolves with cv module
462
462
  */
463
463
  async function loadOpenCV(timeout = 30000) {
464
- console.log('[FaceDetectionEngine] loadOpenCV: START');
465
464
  try {
466
465
  // 快速检查是否已经初始化完成
467
466
  if (opencvInitialized) {
468
- console.log('[FaceDetectionEngine] loadOpenCV: Already initialized, returning immediately');
467
+ console.log('[loadOpenCV] Already initialized, returning immediately');
469
468
  const cv = getCvSync();
470
469
  if (cv) {
471
470
  return { cv };
472
471
  }
473
472
  }
474
473
  // 等待初始化
475
- console.log('[FaceDetectionEngine] loadOpenCV: Waiting for initialization...');
474
+ console.log('[loadOpenCV] Waiting for initialization...');
476
475
  if (!opencvInitPromise) {
477
- console.log('[FaceDetectionEngine] loadOpenCV: Starting new initialization');
476
+ console.log('[loadOpenCV] Starting new initialization');
478
477
  opencvInitPromise = _initializeOpenCV(timeout);
479
478
  }
480
- console.log('[FaceDetectionEngine] loadOpenCV: Awaiting opencvInitPromise');
479
+ console.log('[loadOpenCV] Awaiting opencvInitPromise');
481
480
  const initTime = await opencvInitPromise;
482
- console.log('[FaceDetectionEngine] loadOpenCV: After await, Promise resolved, cost :', initTime.toFixed(0), 'ms');
483
481
  // 清除 Promise 缓存
484
482
  opencvInitPromise = null;
485
483
  // 获取初始化后的 cv 对象
486
484
  const cv = getCvSync();
487
485
  if (!cv) {
488
- console.error('[FaceDetectionEngine] loadOpenCV: getCvSync returned null');
486
+ console.error('[loadOpenCV] getCvSync returned null');
489
487
  throw new Error('OpenCV module is invalid');
490
488
  }
491
- console.log('[FaceDetectionEngine] loadOpenCV: SUCCESS');
492
- return { cv };
489
+ console.log('[loadOpenCV] OpenCV.js load successfully', {
490
+ initTime: `${initTime.toFixed(2)}ms`,
491
+ version: getOpenCVVersion()
492
+ });
493
+ return cv;
493
494
  }
494
495
  catch (error) {
495
- console.error('[FaceDetectionEngine] loadOpenCV: ERROR', error);
496
+ console.error('[loadOpenCV] OpenCV.js load failed', error);
496
497
  opencvInitPromise = null;
497
498
  throw error;
498
499
  }
@@ -512,6 +513,35 @@ function getCvSync() {
512
513
  }
513
514
  return null;
514
515
  }
516
+ /**
517
+ * Extract OpenCV version from getBuildInformation
518
+ * @returns version string like "4.12.0"
519
+ */
520
+ function getOpenCVVersion() {
521
+ try {
522
+ const cv = getCvSync();
523
+ if (!cv || !cv.getBuildInformation) {
524
+ return 'unknown';
525
+ }
526
+ const buildInfo = cv.getBuildInformation();
527
+ // 查找 "Version control:" 或 "OpenCV" 开头的行
528
+ // 格式: "Version control: 4.12.0"
529
+ const versionMatch = buildInfo.match(/Version\s+control:\s+(\d+\.\d+\.\d+)/i);
530
+ if (versionMatch && versionMatch[1]) {
531
+ return versionMatch[1];
532
+ }
533
+ // 备用方案:查找 "OpenCV X.X.X" 格式
534
+ const opencvMatch = buildInfo.match(/OpenCV\s+(\d+\.\d+\.\d+)/i);
535
+ if (opencvMatch && opencvMatch[1]) {
536
+ return opencvMatch[1];
537
+ }
538
+ return 'unknown';
539
+ }
540
+ catch (error) {
541
+ console.error('[getOpenCVVersion] Failed to get version:', error);
542
+ return 'unknown';
543
+ }
544
+ }
515
545
  /**
516
546
  * Load Human.js
517
547
  * @param modelPath - Path to model files (optional)
@@ -541,24 +571,17 @@ async function loadHuman(modelPath, wasmPath) {
541
571
  if (wasmPath) {
542
572
  config.wasmPath = wasmPath;
543
573
  }
544
- console.log('[FaceDetectionEngine] Human.js config:', {
574
+ console.log('[loadHuman] Config:', {
545
575
  backend: config.backend,
546
576
  modelBasePath: config.modelBasePath || '(using default)',
547
577
  wasmPath: config.wasmPath || '(using default)'
548
578
  });
549
579
  const initStartTime = performance.now();
550
- console.log('[FaceDetectionEngine] Creating Human instance...');
551
580
  const human = new Human(config);
552
- const instanceCreateTime = performance.now() - initStartTime;
553
- console.log(`[FaceDetectionEngine] Human instance created, took ${instanceCreateTime.toFixed(2)}ms`);
554
- console.log('[FaceDetectionEngine] Loading Human.js models...');
555
- const modelLoadStartTime = performance.now();
556
581
  try {
557
582
  await human.load();
558
- const loadTime = performance.now() - modelLoadStartTime;
559
583
  const totalTime = performance.now() - initStartTime;
560
- console.log('[FaceDetectionEngine] Human.js loaded successfully', {
561
- modelLoadTime: `${loadTime.toFixed(2)}ms`,
584
+ console.log('[loadHuman] Loaded successfully', {
562
585
  totalInitTime: `${totalTime.toFixed(2)}ms`,
563
586
  version: human.version
564
587
  });
@@ -566,7 +589,32 @@ async function loadHuman(modelPath, wasmPath) {
566
589
  }
567
590
  catch (error) {
568
591
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
569
- console.error('[FaceDetectionEngine] Human.js load failed:', errorMsg);
592
+ console.error('[loadHuman] Load failed:', errorMsg);
593
+ throw error;
594
+ }
595
+ }
596
+ async function loadLibraries(modelPath, wasmPath, timeout) {
597
+ console.log('[loadLibraries] Starting parallel load of OpenCV and Human...');
598
+ const startTime = performance.now();
599
+ if (timeout == undefined) {
600
+ timeout = 30000;
601
+ }
602
+ try {
603
+ // 并行加载 OpenCV 和 Human
604
+ const [cv, human] = await Promise.all([
605
+ loadOpenCV(timeout),
606
+ loadHuman(modelPath, wasmPath)
607
+ ]);
608
+ const totalTime = performance.now() - startTime;
609
+ console.log('[loadLibraries] Both libraries loaded successfully in', totalTime.toFixed(2), 'ms');
610
+ return {
611
+ cv,
612
+ human
613
+ };
614
+ }
615
+ catch (error) {
616
+ const errorMsg = error instanceof Error ? error.message : 'Unknown error';
617
+ console.error('[loadLibraries] Failed to load libraries:', errorMsg);
570
618
  throw error;
571
619
  }
572
620
  }
@@ -1548,12 +1596,13 @@ class FaceDetectionEngine extends SimpleEventEmitter {
1548
1596
  this.isInitializing = true;
1549
1597
  this.emitDebug('initialization', 'Starting to load detection libraries...');
1550
1598
  try {
1551
- // Load OpenCV
1552
- this.emitDebug('initialization', 'Loading OpenCV...');
1553
- const { cv } = await loadOpenCV(300000); // 5 minute timeout
1599
+ // Load Libraries
1600
+ this.emitDebug('initialization', 'Loading Libraries...');
1601
+ const startLoadTime = performance.now();
1602
+ const { cv, human } = await loadLibraries(this.config.human_model_path, this.config.tensorflow_wasm_path, 30000);
1554
1603
  if (!cv || !cv.Mat) {
1555
1604
  console.log('[FaceDetectionEngine] Failed to load OpenCV.js: module is null or invalid');
1556
- this.emit('detector-error', {
1605
+ this.emit('detector-loaded', {
1557
1606
  success: false,
1558
1607
  error: 'Failed to load OpenCV.js: module is null or invalid'
1559
1608
  });
@@ -1563,22 +1612,9 @@ class FaceDetectionEngine extends SimpleEventEmitter {
1563
1612
  });
1564
1613
  return;
1565
1614
  }
1566
- this.emitDebug('initialization', 'OpenCV loaded successfully', {
1567
- version: cv?.getBuildInformation?.() || 'unknown'
1568
- });
1569
- console.log('[FaceDetectionEngine] OpenCV loaded successfully', {
1570
- version: cv?.getBuildInformation?.() || 'unknown'
1571
- });
1572
- // Load Human.js
1573
- console.log('[FaceDetectionEngine] Loading Human.js models...');
1574
- this.emitDebug('initialization', 'Loading Human.js...');
1575
- const humanStartTime = performance.now();
1576
- this.human = await loadHuman(this.config.human_model_path, this.config.tensorflow_wasm_path);
1577
- const humanLoadTime = performance.now() - humanStartTime;
1578
1615
  if (!this.human) {
1579
1616
  const errorMsg = 'Failed to load Human.js: instance is null';
1580
1617
  console.log('[FaceDetectionEngine] ' + errorMsg);
1581
- this.emitDebug('initialization', errorMsg, { loadTime: humanLoadTime }, 'error');
1582
1618
  this.emit('detector-loaded', {
1583
1619
  success: false,
1584
1620
  error: errorMsg
@@ -1589,21 +1625,14 @@ class FaceDetectionEngine extends SimpleEventEmitter {
1589
1625
  });
1590
1626
  return;
1591
1627
  }
1592
- this.emitDebug('initialization', 'Human.js loaded successfully', {
1593
- loadTime: `${humanLoadTime.toFixed(2)}ms`,
1594
- version: this.human.version
1595
- });
1596
- console.log('[FaceDetectionEngine] Human.js loaded successfully', {
1597
- loadTime: `${humanLoadTime.toFixed(2)}ms`,
1598
- version: this.human.version
1599
- });
1600
1628
  this.isReady = true;
1601
1629
  const loadedData = {
1602
1630
  success: true,
1603
- opencv_version: cv?.getBuildInformation?.() || 'unknown',
1631
+ opencv_version: getOpenCVVersion(),
1604
1632
  human_version: this.human.version
1605
1633
  };
1606
1634
  console.log('[FaceDetectionEngine] Engine initialized and ready', {
1635
+ initCostTime: (performance.now() - startLoadTime).toFixed(2),
1607
1636
  opencv_version: loadedData.opencv_version,
1608
1637
  human_version: loadedData.human_version
1609
1638
  });
@@ -2373,5 +2402,5 @@ class FaceDetectionEngine extends SimpleEventEmitter {
2373
2402
  }
2374
2403
  }
2375
2404
 
2376
- export { DetectionPeriod, ErrorCode, FaceDetectionEngine, LivenessAction, LivenessActionStatus, PromptCode, FaceDetectionEngine as default, getCvSync, loadOpenCV, preloadOpenCV };
2405
+ export { DetectionPeriod, ErrorCode, FaceDetectionEngine, LivenessAction, LivenessActionStatus, PromptCode, FaceDetectionEngine as default, getCvSync, getOpenCVVersion, loadOpenCV, preloadOpenCV };
2377
2406
  //# sourceMappingURL=index.esm.js.map