@sssxyd/face-liveness-detector 0.2.33 → 0.2.35

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
@@ -332,6 +332,43 @@ function _detectBrowserEngine(userAgent) {
332
332
  // 4. 其他浏览器 - 保守方案,使用 WASM
333
333
  return 'other';
334
334
  }
335
+ /**
336
+ * 检测环境信息(用于诊断)
337
+ */
338
+ function _detectEnvironmentInfo() {
339
+ const isMobile = /android|iphone|ipad|ipod|opera mini|iemobile|wpdesktop/i.test(navigator.userAgent.toLowerCase());
340
+ const isAndroid = /android/i.test(navigator.userAgent);
341
+ const isIOS = /iphone|ipad|ipod/i.test(navigator.userAgent);
342
+ // 检测内存
343
+ let memory = { available: 'unknown' };
344
+ if (navigator.deviceMemory) {
345
+ memory = { available: `${navigator.deviceMemory}GB` };
346
+ }
347
+ // 检测连接
348
+ let connection = { type: 'unknown' };
349
+ if (navigator.connection) {
350
+ const conn = navigator.connection;
351
+ connection = {
352
+ type: conn.effectiveType,
353
+ downlink: `${conn.downlink}Mbps`,
354
+ rtt: `${conn.rtt}ms`,
355
+ saveData: conn.saveData
356
+ };
357
+ }
358
+ return {
359
+ isMobile,
360
+ isAndroid,
361
+ isIOS,
362
+ memory,
363
+ connection,
364
+ userAgent: navigator.userAgent,
365
+ platform: navigator.platform,
366
+ language: navigator.language,
367
+ hardwareConcurrency: navigator.hardwareConcurrency,
368
+ maxTouchPoints: navigator.maxTouchPoints,
369
+ vendor: navigator.vendor
370
+ };
371
+ }
335
372
  function _getOptimalBackendForEngine(engine) {
336
373
  // 针对不同内核的优化策略
337
374
  const backendConfig = {
@@ -605,14 +642,28 @@ async function _loadAndVerifyHuman(human) {
605
642
  catch (error) {
606
643
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
607
644
  const errorStack = error instanceof Error ? error.stack : 'N/A';
645
+ const isCORSError = errorMsg.toLowerCase().includes('cors') ||
646
+ errorMsg.toLowerCase().includes('cross-origin') ||
647
+ errorMsg.toLowerCase().includes('blocked by cors policy');
648
+ const isNetworkError = errorMsg.toLowerCase().includes('network') ||
649
+ errorMsg.toLowerCase().includes('failed to fetch') ||
650
+ errorMsg.toLowerCase().includes('fetch failed');
651
+ const isWASMError = errorMsg.toLowerCase().includes('wasm') ||
652
+ errorMsg.toLowerCase().includes('webassembly');
608
653
  console.error('[FaceDetectionEngine] Error during human.load():', {
609
654
  errorMsg,
610
655
  stack: errorStack,
611
656
  backend: human.config?.backend,
612
657
  hasModels: !!human.models,
613
- modelsKeys: human.models ? Object.keys(human.models).length : 0
658
+ modelsKeys: human.models ? Object.keys(human.models).length : 0,
659
+ isCORSError,
660
+ isNetworkError,
661
+ isWASMError,
662
+ modelBasePath: human.config?.modelBasePath,
663
+ wasmPath: human.config?.wasmPath,
664
+ userAgent: navigator.userAgent
614
665
  });
615
- throw new Error(`Model loading error: ${errorMsg}`);
666
+ throw new Error(`Model loading error (${human.config?.backend} backend): ${errorMsg}`);
616
667
  }
617
668
  const loadTime = performance.now() - modelLoadStartTime;
618
669
  console.log('[FaceDetectionEngine] Human.js loaded successfully', {
@@ -632,54 +683,14 @@ async function _loadAndVerifyHuman(human) {
632
683
  console.error('[FaceDetectionEngine] CRITICAL: human.models is empty after loading!');
633
684
  throw new Error('No models were loaded - human.models is empty');
634
685
  }
635
- // 详细检查每个关键模型及其结构
636
- const criticalModels = ['face', 'antispoof', 'liveness'];
637
- const missingModels = [];
638
- for (const modelName of criticalModels) {
639
- const model = human.models[modelName];
640
- if (!model) {
641
- missingModels.push(modelName);
642
- console.error(`[FaceDetectionEngine] CRITICAL: Model '${modelName}' is missing!`);
643
- }
644
- else {
645
- const isLoaded = model.loaded || model.state === 'loaded' || !!model.model;
646
- // 检查模型是否有必要的内部结构(防止 "Cannot read properties of undefined (reading 'inputs')" 错误)
647
- const hasExecutor = !!model['executor'];
648
- const hasInputs = !!model.inputs && Array.isArray(model.inputs) && model.inputs.length > 0;
649
- const hasModelUrl = !!model['modelUrl'];
650
- console.log(`[FaceDetectionEngine] Model '${modelName}':`, {
651
- loaded: isLoaded,
652
- state: model.state,
653
- hasModel: !!model.model,
654
- hasExecutor,
655
- hasInputs,
656
- hasModelUrl,
657
- inputsType: typeof model.inputs,
658
- inputsLength: Array.isArray(model.inputs) ? model.inputs.length : 'N/A'
659
- });
660
- // 严格检查:模型必须有以下结构才能正常工作
661
- if (!isLoaded || !hasExecutor || !hasModelUrl) {
662
- missingModels.push(`${modelName} (incomplete)`);
663
- console.error(`[FaceDetectionEngine] WARNING: Model '${modelName}' may not be fully loaded - missing structure`);
664
- }
665
- // 如果 inputs 未定义会导致 "Cannot read properties of undefined (reading 'inputs')" 错误
666
- if (!hasInputs && modelName !== 'antispoof') {
667
- console.warn(`[FaceDetectionEngine] WARNING: Model '${modelName}' has no inputs - may cause errors during detection`);
668
- missingModels.push(`${modelName} (no inputs)`);
669
- }
670
- }
671
- }
672
- if (missingModels.length > 0) {
673
- console.error('[FaceDetectionEngine] Some critical models failed to load:', missingModels);
674
- throw new Error(`Critical models not loaded: ${missingModels.join(', ')}`);
675
- }
676
686
  // 打印加载的模型信息
677
687
  if (human.models) {
678
688
  const loadedModels = Object.entries(human.models).map(([name, model]) => ({
679
689
  name,
680
690
  loaded: model?.loaded || model?.state === 'loaded',
681
691
  type: typeof model,
682
- hasModel: !!model?.model
692
+ hasModel: !!model?.model,
693
+ keys: Object.keys(model).length
683
694
  }));
684
695
  console.log('[FaceDetectionEngine] All loaded models:', {
685
696
  backend: human.config?.backend,
@@ -711,7 +722,11 @@ async function _tryLoadHumanWithBackend(backend, modelPath, wasmPath) {
711
722
  errorMsg,
712
723
  stack,
713
724
  backend: config.backend,
714
- userAgent: navigator.userAgent
725
+ userAgent: navigator.userAgent,
726
+ isCORSError: errorMsg.toLowerCase().includes('cors'),
727
+ isNetworkError: errorMsg.toLowerCase().includes('network'),
728
+ isWASMError: errorMsg.toLowerCase().includes('wasm'),
729
+ environmentInfo: _detectEnvironmentInfo()
715
730
  });
716
731
  return null;
717
732
  }
@@ -720,11 +735,8 @@ async function _tryLoadHumanWithBackend(backend, modelPath, wasmPath) {
720
735
  console.error(`[FaceDetectionEngine] Human instance is null (${backend})`);
721
736
  return null;
722
737
  }
723
- // 验证 Human 实例结构(早期检测 WASM 问题)
724
- if (!human.config) {
725
- console.warn('[FaceDetectionEngine] Warning: human.config is missing');
726
- }
727
738
  try {
739
+ console.log(`[FaceDetectionEngine] Starting model loading for ${backend} backend...`);
728
740
  await _loadAndVerifyHuman(human);
729
741
  const totalTime = performance.now() - initStartTime;
730
742
  console.log(`[FaceDetectionEngine] Successfully loaded Human.js with ${backend} backend in ${totalTime.toFixed(2)}ms`);
@@ -732,7 +744,19 @@ async function _tryLoadHumanWithBackend(backend, modelPath, wasmPath) {
732
744
  }
733
745
  catch (error) {
734
746
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
735
- console.error(`[FaceDetectionEngine] Failed to load models with ${backend} backend:`, errorMsg);
747
+ const stack = error instanceof Error ? error.stack : 'N/A';
748
+ console.error(`[FaceDetectionEngine] Failed to load models with ${backend} backend:`, {
749
+ errorMsg,
750
+ stack,
751
+ backend,
752
+ modelPath,
753
+ wasmPath,
754
+ isCORSError: errorMsg.toLowerCase().includes('cors') || errorMsg.toLowerCase().includes('cross-origin'),
755
+ isNetworkError: errorMsg.toLowerCase().includes('network') || errorMsg.toLowerCase().includes('failed to fetch'),
756
+ isWASMError: errorMsg.toLowerCase().includes('wasm'),
757
+ duration: `${(performance.now() - initStartTime).toFixed(2)}ms`,
758
+ environmentInfo: _detectEnvironmentInfo()
759
+ });
736
760
  return null;
737
761
  }
738
762
  }
@@ -745,14 +769,15 @@ async function _tryLoadHumanWithBackend(backend, modelPath, wasmPath) {
745
769
  */
746
770
  async function loadHuman(modelPath, wasmPath, preferredBackend) {
747
771
  const selectedBackend = _detectOptimalBackend(preferredBackend);
772
+ const environmentInfo = _detectEnvironmentInfo();
748
773
  console.log('[FaceDetectionEngine] Starting Human.js initialization:', {
749
774
  selectedBackend,
750
775
  modelBasePath: modelPath || '(using default)',
751
776
  wasmPath: wasmPath || '(using default)',
752
- userAgent: navigator.userAgent,
753
- platform: navigator.platform
777
+ ...environmentInfo
754
778
  });
755
779
  // 尝试用主后端加载
780
+ console.log(`[FaceDetectionEngine] Attempting to load Human.js with ${selectedBackend} backend...`);
756
781
  const human = await _tryLoadHumanWithBackend(selectedBackend, modelPath, wasmPath);
757
782
  if (human) {
758
783
  return human;
@@ -770,11 +795,38 @@ async function loadHuman(modelPath, wasmPath, preferredBackend) {
770
795
  console.warn(`[FaceDetectionEngine] Primary backend (${selectedBackend}) failed, attempting fallback to ${fallbackBackend}...`);
771
796
  const humanFallback = await _tryLoadHumanWithBackend(fallbackBackend, modelPath, wasmPath);
772
797
  if (humanFallback) {
798
+ console.log(`[FaceDetectionEngine] Successfully loaded with fallback backend: ${fallbackBackend}`);
773
799
  return humanFallback;
774
800
  }
775
- throw new Error(`Human.js loading failed: both ${selectedBackend} and ${fallbackBackend} backends failed`);
776
- }
777
- throw new Error(`Human.js loading failed: ${selectedBackend} backend failed (no fallback available)`);
801
+ const errorDetails = {
802
+ message: `Human.js loading failed: both ${selectedBackend} and ${fallbackBackend} backends failed`,
803
+ backends: {
804
+ primary: selectedBackend,
805
+ fallback: fallbackBackend,
806
+ both_failed: true
807
+ },
808
+ environment: environmentInfo,
809
+ paths: {
810
+ modelBasePath: modelPath || '(using default)',
811
+ wasmPath: wasmPath || '(using default)'
812
+ },
813
+ webglAvailable: _isWebGLAvailable()
814
+ };
815
+ console.error('[FaceDetectionEngine] CRITICAL ERROR:', errorDetails);
816
+ throw new Error(errorDetails.message);
817
+ }
818
+ const errorDetails = {
819
+ message: `Human.js loading failed: ${selectedBackend} backend failed (no fallback available)`,
820
+ backend: selectedBackend,
821
+ environment: environmentInfo,
822
+ paths: {
823
+ modelBasePath: modelPath || '(using default)',
824
+ wasmPath: wasmPath || '(using default)'
825
+ },
826
+ webglAvailable: _isWebGLAvailable()
827
+ };
828
+ console.error('[FaceDetectionEngine] CRITICAL ERROR:', errorDetails);
829
+ throw new Error(errorDetails.message);
778
830
  }
779
831
  /**
780
832
  * Extract OpenCV version from getBuildInformation