@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.js CHANGED
@@ -354,6 +354,43 @@
354
354
  // 4. 其他浏览器 - 保守方案,使用 WASM
355
355
  return 'other';
356
356
  }
357
+ /**
358
+ * 检测环境信息(用于诊断)
359
+ */
360
+ function _detectEnvironmentInfo() {
361
+ const isMobile = /android|iphone|ipad|ipod|opera mini|iemobile|wpdesktop/i.test(navigator.userAgent.toLowerCase());
362
+ const isAndroid = /android/i.test(navigator.userAgent);
363
+ const isIOS = /iphone|ipad|ipod/i.test(navigator.userAgent);
364
+ // 检测内存
365
+ let memory = { available: 'unknown' };
366
+ if (navigator.deviceMemory) {
367
+ memory = { available: `${navigator.deviceMemory}GB` };
368
+ }
369
+ // 检测连接
370
+ let connection = { type: 'unknown' };
371
+ if (navigator.connection) {
372
+ const conn = navigator.connection;
373
+ connection = {
374
+ type: conn.effectiveType,
375
+ downlink: `${conn.downlink}Mbps`,
376
+ rtt: `${conn.rtt}ms`,
377
+ saveData: conn.saveData
378
+ };
379
+ }
380
+ return {
381
+ isMobile,
382
+ isAndroid,
383
+ isIOS,
384
+ memory,
385
+ connection,
386
+ userAgent: navigator.userAgent,
387
+ platform: navigator.platform,
388
+ language: navigator.language,
389
+ hardwareConcurrency: navigator.hardwareConcurrency,
390
+ maxTouchPoints: navigator.maxTouchPoints,
391
+ vendor: navigator.vendor
392
+ };
393
+ }
357
394
  function _getOptimalBackendForEngine(engine) {
358
395
  // 针对不同内核的优化策略
359
396
  const backendConfig = {
@@ -627,14 +664,28 @@
627
664
  catch (error) {
628
665
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
629
666
  const errorStack = error instanceof Error ? error.stack : 'N/A';
667
+ const isCORSError = errorMsg.toLowerCase().includes('cors') ||
668
+ errorMsg.toLowerCase().includes('cross-origin') ||
669
+ errorMsg.toLowerCase().includes('blocked by cors policy');
670
+ const isNetworkError = errorMsg.toLowerCase().includes('network') ||
671
+ errorMsg.toLowerCase().includes('failed to fetch') ||
672
+ errorMsg.toLowerCase().includes('fetch failed');
673
+ const isWASMError = errorMsg.toLowerCase().includes('wasm') ||
674
+ errorMsg.toLowerCase().includes('webassembly');
630
675
  console.error('[FaceDetectionEngine] Error during human.load():', {
631
676
  errorMsg,
632
677
  stack: errorStack,
633
678
  backend: human.config?.backend,
634
679
  hasModels: !!human.models,
635
- modelsKeys: human.models ? Object.keys(human.models).length : 0
680
+ modelsKeys: human.models ? Object.keys(human.models).length : 0,
681
+ isCORSError,
682
+ isNetworkError,
683
+ isWASMError,
684
+ modelBasePath: human.config?.modelBasePath,
685
+ wasmPath: human.config?.wasmPath,
686
+ userAgent: navigator.userAgent
636
687
  });
637
- throw new Error(`Model loading error: ${errorMsg}`);
688
+ throw new Error(`Model loading error (${human.config?.backend} backend): ${errorMsg}`);
638
689
  }
639
690
  const loadTime = performance.now() - modelLoadStartTime;
640
691
  console.log('[FaceDetectionEngine] Human.js loaded successfully', {
@@ -654,54 +705,14 @@
654
705
  console.error('[FaceDetectionEngine] CRITICAL: human.models is empty after loading!');
655
706
  throw new Error('No models were loaded - human.models is empty');
656
707
  }
657
- // 详细检查每个关键模型及其结构
658
- const criticalModels = ['face', 'antispoof', 'liveness'];
659
- const missingModels = [];
660
- for (const modelName of criticalModels) {
661
- const model = human.models[modelName];
662
- if (!model) {
663
- missingModels.push(modelName);
664
- console.error(`[FaceDetectionEngine] CRITICAL: Model '${modelName}' is missing!`);
665
- }
666
- else {
667
- const isLoaded = model.loaded || model.state === 'loaded' || !!model.model;
668
- // 检查模型是否有必要的内部结构(防止 "Cannot read properties of undefined (reading 'inputs')" 错误)
669
- const hasExecutor = !!model['executor'];
670
- const hasInputs = !!model.inputs && Array.isArray(model.inputs) && model.inputs.length > 0;
671
- const hasModelUrl = !!model['modelUrl'];
672
- console.log(`[FaceDetectionEngine] Model '${modelName}':`, {
673
- loaded: isLoaded,
674
- state: model.state,
675
- hasModel: !!model.model,
676
- hasExecutor,
677
- hasInputs,
678
- hasModelUrl,
679
- inputsType: typeof model.inputs,
680
- inputsLength: Array.isArray(model.inputs) ? model.inputs.length : 'N/A'
681
- });
682
- // 严格检查:模型必须有以下结构才能正常工作
683
- if (!isLoaded || !hasExecutor || !hasModelUrl) {
684
- missingModels.push(`${modelName} (incomplete)`);
685
- console.error(`[FaceDetectionEngine] WARNING: Model '${modelName}' may not be fully loaded - missing structure`);
686
- }
687
- // 如果 inputs 未定义会导致 "Cannot read properties of undefined (reading 'inputs')" 错误
688
- if (!hasInputs && modelName !== 'antispoof') {
689
- console.warn(`[FaceDetectionEngine] WARNING: Model '${modelName}' has no inputs - may cause errors during detection`);
690
- missingModels.push(`${modelName} (no inputs)`);
691
- }
692
- }
693
- }
694
- if (missingModels.length > 0) {
695
- console.error('[FaceDetectionEngine] Some critical models failed to load:', missingModels);
696
- throw new Error(`Critical models not loaded: ${missingModels.join(', ')}`);
697
- }
698
708
  // 打印加载的模型信息
699
709
  if (human.models) {
700
710
  const loadedModels = Object.entries(human.models).map(([name, model]) => ({
701
711
  name,
702
712
  loaded: model?.loaded || model?.state === 'loaded',
703
713
  type: typeof model,
704
- hasModel: !!model?.model
714
+ hasModel: !!model?.model,
715
+ keys: Object.keys(model).length
705
716
  }));
706
717
  console.log('[FaceDetectionEngine] All loaded models:', {
707
718
  backend: human.config?.backend,
@@ -733,7 +744,11 @@
733
744
  errorMsg,
734
745
  stack,
735
746
  backend: config.backend,
736
- userAgent: navigator.userAgent
747
+ userAgent: navigator.userAgent,
748
+ isCORSError: errorMsg.toLowerCase().includes('cors'),
749
+ isNetworkError: errorMsg.toLowerCase().includes('network'),
750
+ isWASMError: errorMsg.toLowerCase().includes('wasm'),
751
+ environmentInfo: _detectEnvironmentInfo()
737
752
  });
738
753
  return null;
739
754
  }
@@ -742,11 +757,8 @@
742
757
  console.error(`[FaceDetectionEngine] Human instance is null (${backend})`);
743
758
  return null;
744
759
  }
745
- // 验证 Human 实例结构(早期检测 WASM 问题)
746
- if (!human.config) {
747
- console.warn('[FaceDetectionEngine] Warning: human.config is missing');
748
- }
749
760
  try {
761
+ console.log(`[FaceDetectionEngine] Starting model loading for ${backend} backend...`);
750
762
  await _loadAndVerifyHuman(human);
751
763
  const totalTime = performance.now() - initStartTime;
752
764
  console.log(`[FaceDetectionEngine] Successfully loaded Human.js with ${backend} backend in ${totalTime.toFixed(2)}ms`);
@@ -754,7 +766,19 @@
754
766
  }
755
767
  catch (error) {
756
768
  const errorMsg = error instanceof Error ? error.message : 'Unknown error';
757
- console.error(`[FaceDetectionEngine] Failed to load models with ${backend} backend:`, errorMsg);
769
+ const stack = error instanceof Error ? error.stack : 'N/A';
770
+ console.error(`[FaceDetectionEngine] Failed to load models with ${backend} backend:`, {
771
+ errorMsg,
772
+ stack,
773
+ backend,
774
+ modelPath,
775
+ wasmPath,
776
+ isCORSError: errorMsg.toLowerCase().includes('cors') || errorMsg.toLowerCase().includes('cross-origin'),
777
+ isNetworkError: errorMsg.toLowerCase().includes('network') || errorMsg.toLowerCase().includes('failed to fetch'),
778
+ isWASMError: errorMsg.toLowerCase().includes('wasm'),
779
+ duration: `${(performance.now() - initStartTime).toFixed(2)}ms`,
780
+ environmentInfo: _detectEnvironmentInfo()
781
+ });
758
782
  return null;
759
783
  }
760
784
  }
@@ -767,14 +791,15 @@
767
791
  */
768
792
  async function loadHuman(modelPath, wasmPath, preferredBackend) {
769
793
  const selectedBackend = _detectOptimalBackend(preferredBackend);
794
+ const environmentInfo = _detectEnvironmentInfo();
770
795
  console.log('[FaceDetectionEngine] Starting Human.js initialization:', {
771
796
  selectedBackend,
772
797
  modelBasePath: modelPath || '(using default)',
773
798
  wasmPath: wasmPath || '(using default)',
774
- userAgent: navigator.userAgent,
775
- platform: navigator.platform
799
+ ...environmentInfo
776
800
  });
777
801
  // 尝试用主后端加载
802
+ console.log(`[FaceDetectionEngine] Attempting to load Human.js with ${selectedBackend} backend...`);
778
803
  const human = await _tryLoadHumanWithBackend(selectedBackend, modelPath, wasmPath);
779
804
  if (human) {
780
805
  return human;
@@ -792,11 +817,38 @@
792
817
  console.warn(`[FaceDetectionEngine] Primary backend (${selectedBackend}) failed, attempting fallback to ${fallbackBackend}...`);
793
818
  const humanFallback = await _tryLoadHumanWithBackend(fallbackBackend, modelPath, wasmPath);
794
819
  if (humanFallback) {
820
+ console.log(`[FaceDetectionEngine] Successfully loaded with fallback backend: ${fallbackBackend}`);
795
821
  return humanFallback;
796
822
  }
797
- throw new Error(`Human.js loading failed: both ${selectedBackend} and ${fallbackBackend} backends failed`);
798
- }
799
- throw new Error(`Human.js loading failed: ${selectedBackend} backend failed (no fallback available)`);
823
+ const errorDetails = {
824
+ message: `Human.js loading failed: both ${selectedBackend} and ${fallbackBackend} backends failed`,
825
+ backends: {
826
+ primary: selectedBackend,
827
+ fallback: fallbackBackend,
828
+ both_failed: true
829
+ },
830
+ environment: environmentInfo,
831
+ paths: {
832
+ modelBasePath: modelPath || '(using default)',
833
+ wasmPath: wasmPath || '(using default)'
834
+ },
835
+ webglAvailable: _isWebGLAvailable()
836
+ };
837
+ console.error('[FaceDetectionEngine] CRITICAL ERROR:', errorDetails);
838
+ throw new Error(errorDetails.message);
839
+ }
840
+ const errorDetails = {
841
+ message: `Human.js loading failed: ${selectedBackend} backend failed (no fallback available)`,
842
+ backend: selectedBackend,
843
+ environment: environmentInfo,
844
+ paths: {
845
+ modelBasePath: modelPath || '(using default)',
846
+ wasmPath: wasmPath || '(using default)'
847
+ },
848
+ webglAvailable: _isWebGLAvailable()
849
+ };
850
+ console.error('[FaceDetectionEngine] CRITICAL ERROR:', errorDetails);
851
+ throw new Error(errorDetails.message);
800
852
  }
801
853
  /**
802
854
  * Extract OpenCV version from getBuildInformation