facecog-liveness-showcase 0.0.1

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.
Files changed (229) hide show
  1. package/.browserslistrc +15 -0
  2. package/.dockerignore +48 -0
  3. package/.editorconfig +16 -0
  4. package/.eslintrc.json +47 -0
  5. package/.vercelignore +7 -0
  6. package/.vscode/extensions.json +5 -0
  7. package/.vscode/settings.json +3 -0
  8. package/DOCKER.md +221 -0
  9. package/Dockerfile +33 -0
  10. package/README.md +268 -0
  11. package/angular.json +156 -0
  12. package/capacitor.config.ts +9 -0
  13. package/docker-compose.dev.yml +20 -0
  14. package/docker-compose.yml +18 -0
  15. package/ionic.config.json +7 -0
  16. package/jest.config.js +38 -0
  17. package/nginx.conf +50 -0
  18. package/package.json +131 -0
  19. package/patches/ng-packagr+20.3.2.patch +60 -0
  20. package/projects/facecog-liveness-verification/README.md +295 -0
  21. package/projects/facecog-liveness-verification/ng-package.json +7 -0
  22. package/projects/facecog-liveness-verification/package.json +48 -0
  23. package/projects/facecog-liveness-verification/scripts/build-with-wrapper-copy.js +38 -0
  24. package/projects/facecog-liveness-verification/scripts/copy-wrapper-after-ngc.js +35 -0
  25. package/projects/facecog-liveness-verification/sources/FaceLivenessReactWrapper.tsx +320 -0
  26. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.d.ts +28 -0
  27. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.js +247 -0
  28. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.js.map +1 -0
  29. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.js.map +1 -0
  30. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.ts +5 -0
  31. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/aws-face-liveness.component.ts +500 -0
  32. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.html +41 -0
  33. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.scss +234 -0
  34. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.spec.ts +158 -0
  35. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.ts +58 -0
  36. package/projects/facecog-liveness-verification/src/lib/components/camera-verification/camera-verification.component.html +34 -0
  37. package/projects/facecog-liveness-verification/src/lib/components/camera-verification/camera-verification.component.ts +210 -0
  38. package/projects/facecog-liveness-verification/src/lib/components/dialogs/save-custom-pose-dialog.component.ts +174 -0
  39. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.html +45 -0
  40. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.scss +87 -0
  41. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.ts +182 -0
  42. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.html +394 -0
  43. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.scss +1567 -0
  44. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.spec.ts +699 -0
  45. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.ts +721 -0
  46. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.html +120 -0
  47. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.scss +611 -0
  48. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.spec.ts +605 -0
  49. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.ts +524 -0
  50. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.html +73 -0
  51. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.scss +19 -0
  52. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.spec.ts +673 -0
  53. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.ts +963 -0
  54. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.html +38 -0
  55. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.scss +10 -0
  56. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.ts +233 -0
  57. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.html +17 -0
  58. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.spec.ts +35 -0
  59. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.ts +33 -0
  60. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.html +17 -0
  61. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.scss +156 -0
  62. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.spec.ts +46 -0
  63. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.ts +18 -0
  64. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.html +190 -0
  65. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.scss +534 -0
  66. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.spec.ts +286 -0
  67. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.ts +155 -0
  68. package/projects/facecog-liveness-verification/src/lib/interfaces/analyze-response.interface.ts +16 -0
  69. package/projects/facecog-liveness-verification/src/lib/interfaces/aws-face-liveness.interface.ts +46 -0
  70. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-adapter.interface.ts +21 -0
  71. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-http-client.interface.ts +93 -0
  72. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-response.interface.ts +9 -0
  73. package/projects/facecog-liveness-verification/src/lib/interfaces/camera-provider.interface.ts +107 -0
  74. package/projects/facecog-liveness-verification/src/lib/interfaces/category-info.interface.ts +9 -0
  75. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-data.interface.ts +14 -0
  76. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-repository.interface.ts +48 -0
  77. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-response.interface.ts +14 -0
  78. package/projects/facecog-liveness-verification/src/lib/interfaces/index.ts +52 -0
  79. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-action-result.interface.ts +13 -0
  80. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-config.interface.ts +17 -0
  81. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-metadata.interface.ts +17 -0
  82. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-result.interface.ts +24 -0
  83. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-verification-config.interface.ts +41 -0
  84. package/projects/facecog-liveness-verification/src/lib/interfaces/multi-backend-analyze-response.interface.ts +21 -0
  85. package/projects/facecog-liveness-verification/src/lib/interfaces/multi-backend-liveness-result.interface.ts +14 -0
  86. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-definition.interface.ts +35 -0
  87. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-keypoint.interface.ts +12 -0
  88. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-match-result.interface.ts +9 -0
  89. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-verify-response.interface.ts +8 -0
  90. package/projects/facecog-liveness-verification/src/lib/interfaces/scan-results.interface.ts +29 -0
  91. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-plan.interface.ts +42 -0
  92. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-progress-event.interface.ts +12 -0
  93. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-session.interface.ts +72 -0
  94. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-step-change-event.interface.ts +11 -0
  95. package/projects/facecog-liveness-verification/src/lib/interfaces/video-recording.interface.ts +9 -0
  96. package/projects/facecog-liveness-verification/src/lib/liveness-verification.module.ts +123 -0
  97. package/projects/facecog-liveness-verification/src/lib/models/constants/aws-face-liveness-component.token.ts +23 -0
  98. package/projects/facecog-liveness-verification/src/lib/models/constants/category-info.constant.ts +14 -0
  99. package/projects/facecog-liveness-verification/src/lib/models/constants/default-liveness-config.constant.ts +18 -0
  100. package/projects/facecog-liveness-verification/src/lib/models/constants/index.ts +5 -0
  101. package/projects/facecog-liveness-verification/src/lib/models/constants/liveness-verification-config.token.ts +16 -0
  102. package/projects/facecog-liveness-verification/src/lib/models/constants/pose-definitions.constant.ts +377 -0
  103. package/projects/facecog-liveness-verification/src/lib/models/index.ts +5 -0
  104. package/projects/facecog-liveness-verification/src/lib/models/utils/index.ts +2 -0
  105. package/projects/facecog-liveness-verification/src/lib/models/utils/pose.utils.spec.ts +76 -0
  106. package/projects/facecog-liveness-verification/src/lib/models/utils/pose.utils.ts +59 -0
  107. package/projects/facecog-liveness-verification/src/lib/services/aws-face-liveness.service.ts +49 -0
  108. package/projects/facecog-liveness-verification/src/lib/services/backend-http.service.spec.ts +111 -0
  109. package/projects/facecog-liveness-verification/src/lib/services/backend-http.service.ts +130 -0
  110. package/projects/facecog-liveness-verification/src/lib/services/backends/azure-backend.service.spec.ts +69 -0
  111. package/projects/facecog-liveness-verification/src/lib/services/backends/azure-backend.service.ts +72 -0
  112. package/projects/facecog-liveness-verification/src/lib/services/backends/facetec-backend.service.spec.ts +24 -0
  113. package/projects/facecog-liveness-verification/src/lib/services/backends/facetec-backend.service.ts +35 -0
  114. package/projects/facecog-liveness-verification/src/lib/services/backends/mock-backend.service.spec.ts +36 -0
  115. package/projects/facecog-liveness-verification/src/lib/services/backends/mock-backend.service.ts +39 -0
  116. package/projects/facecog-liveness-verification/src/lib/services/backends/openpose-backend.service.spec.ts +81 -0
  117. package/projects/facecog-liveness-verification/src/lib/services/backends/openpose-backend.service.ts +72 -0
  118. package/projects/facecog-liveness-verification/src/lib/services/backends/rekognition-analysis-backend.service.spec.ts +69 -0
  119. package/projects/facecog-liveness-verification/src/lib/services/backends/rekognition-analysis-backend.service.ts +83 -0
  120. package/projects/facecog-liveness-verification/src/lib/services/camera.service.spec.ts +200 -0
  121. package/projects/facecog-liveness-verification/src/lib/services/camera.service.ts +155 -0
  122. package/projects/facecog-liveness-verification/src/lib/services/custom-poses-api.service.ts +117 -0
  123. package/projects/facecog-liveness-verification/src/lib/services/index.ts +18 -0
  124. package/projects/facecog-liveness-verification/src/lib/services/liveness-backend.service.spec.ts +103 -0
  125. package/projects/facecog-liveness-verification/src/lib/services/liveness-backend.service.ts +61 -0
  126. package/projects/facecog-liveness-verification/src/lib/services/liveness-config.service.spec.ts +109 -0
  127. package/projects/facecog-liveness-verification/src/lib/services/liveness-config.service.ts +70 -0
  128. package/projects/facecog-liveness-verification/src/lib/services/liveness-orchestrator.service.spec.ts +144 -0
  129. package/projects/facecog-liveness-verification/src/lib/services/liveness-orchestrator.service.ts +162 -0
  130. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/hand-gesture-detection.service.ts +315 -0
  131. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/index.ts +5 -0
  132. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/openpose.service.ts +287 -0
  133. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/pose-comparison.service.ts +353 -0
  134. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/pose-matching.service.ts +2370 -0
  135. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/reference-pose.service.ts +271 -0
  136. package/projects/facecog-liveness-verification/src/lib/services/pose-selection.service.spec.ts +183 -0
  137. package/projects/facecog-liveness-verification/src/lib/services/pose-selection.service.ts +179 -0
  138. package/projects/facecog-liveness-verification/src/lib/services/verification-api.service.spec.ts +159 -0
  139. package/projects/facecog-liveness-verification/src/lib/services/verification-api.service.ts +151 -0
  140. package/projects/facecog-liveness-verification/src/lib/services/verification-plan.service.spec.ts +184 -0
  141. package/projects/facecog-liveness-verification/src/lib/services/verification-plan.service.ts +94 -0
  142. package/projects/facecog-liveness-verification/src/lib/services/video-recorder.service.spec.ts +52 -0
  143. package/projects/facecog-liveness-verification/src/lib/services/video-recorder.service.ts +117 -0
  144. package/projects/facecog-liveness-verification/src/lib/types/detection-strategy.type.ts +5 -0
  145. package/projects/facecog-liveness-verification/src/lib/types/index.ts +7 -0
  146. package/projects/facecog-liveness-verification/src/lib/types/liveness-action.type.ts +31 -0
  147. package/projects/facecog-liveness-verification/src/lib/types/liveness-backend.type.ts +5 -0
  148. package/projects/facecog-liveness-verification/src/lib/types/pose-category.type.ts +5 -0
  149. package/projects/facecog-liveness-verification/src/lib/types/pose-difficulty.type.ts +5 -0
  150. package/projects/facecog-liveness-verification/src/lib/types/verification-flow-step.type.ts +5 -0
  151. package/projects/facecog-liveness-verification/src/lib/types/verification-step-kind.type.ts +4 -0
  152. package/projects/facecog-liveness-verification/src/public-api.ts +150 -0
  153. package/projects/facecog-liveness-verification/tsconfig.lib.json +20 -0
  154. package/projects/facecog-liveness-verification/tsconfig.lib.prod.json +11 -0
  155. package/projects/facecog-liveness-verification/tsconfig.spec.json +13 -0
  156. package/projects/facecog-liveness-verification/tsconfig.wrapper.json +15 -0
  157. package/projects/facecog-liveness-verification-test/src/app/app-routing.module.ts +22 -0
  158. package/projects/facecog-liveness-verification-test/src/app/app.component.html +3 -0
  159. package/projects/facecog-liveness-verification-test/src/app/app.component.scss +0 -0
  160. package/projects/facecog-liveness-verification-test/src/app/app.component.ts +11 -0
  161. package/projects/facecog-liveness-verification-test/src/app/app.module.ts +27 -0
  162. package/projects/facecog-liveness-verification-test/src/app/home/home-routing.module.ts +16 -0
  163. package/projects/facecog-liveness-verification-test/src/app/home/home.module.ts +19 -0
  164. package/projects/facecog-liveness-verification-test/src/app/home/home.page.html +39 -0
  165. package/projects/facecog-liveness-verification-test/src/app/home/home.page.scss +97 -0
  166. package/projects/facecog-liveness-verification-test/src/app/home/home.page.spec.ts +24 -0
  167. package/projects/facecog-liveness-verification-test/src/app/home/home.page.ts +92 -0
  168. package/projects/facecog-liveness-verification-test/src/app/home/verification-modal.component.ts +106 -0
  169. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Bold_0.ttf +0 -0
  170. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Medium_0.ttf +0 -0
  171. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Regular_0.ttf +0 -0
  172. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-SemiBold_0.ttf +0 -0
  173. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Thin_0.ttf +0 -0
  174. package/projects/facecog-liveness-verification-test/src/assets/icon/favicon.png +0 -0
  175. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Five_Fingers_Left.jpg +0 -0
  176. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Left_Palm.jpg +0 -0
  177. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Ok_Sign_Right.jpg +0 -0
  178. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Peace_Sign_Left.jpg +0 -0
  179. package/projects/facecog-liveness-verification-test/src/assets/images/poses/README.md +77 -0
  180. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Right_Palm.jpg +0 -0
  181. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Speak_Phrase.jpg +0 -0
  182. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Three_Fingers_Right.jpg +0 -0
  183. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Thumbs_Up_Left.jpg +0 -0
  184. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Thumbs_Up_Right.jpg +0 -0
  185. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Wave_Right.jpg +0 -0
  186. package/projects/facecog-liveness-verification-test/src/assets/images/poses/blink.jpeg +0 -0
  187. package/projects/facecog-liveness-verification-test/src/assets/images/poses/blink_twice.jpeg +0 -0
  188. package/projects/facecog-liveness-verification-test/src/assets/images/poses/center_face.png +0 -0
  189. package/projects/facecog-liveness-verification-test/src/assets/images/poses/clap.jpeg +0 -0
  190. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cover_mouth.png +0 -0
  191. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cover_right_eye.png +0 -0
  192. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cross_arms.png +0 -0
  193. package/projects/facecog-liveness-verification-test/src/assets/images/poses/face_straight.png +0 -0
  194. package/projects/facecog-liveness-verification-test/src/assets/images/poses/follow_dot.png +0 -0
  195. package/projects/facecog-liveness-verification-test/src/assets/images/poses/look_down.png +0 -0
  196. package/projects/facecog-liveness-verification-test/src/assets/images/poses/look_up.png +0 -0
  197. package/projects/facecog-liveness-verification-test/src/assets/images/poses/move_closer.png +0 -0
  198. package/projects/facecog-liveness-verification-test/src/assets/images/poses/nod.png +0 -0
  199. package/projects/facecog-liveness-verification-test/src/assets/images/poses/open_mouth.png +0 -0
  200. package/projects/facecog-liveness-verification-test/src/assets/images/poses/raise_eyebrow.png +0 -0
  201. package/projects/facecog-liveness-verification-test/src/assets/images/poses/rotate_face.jpeg +0 -0
  202. package/projects/facecog-liveness-verification-test/src/assets/images/poses/shake_head.jpeg +0 -0
  203. package/projects/facecog-liveness-verification-test/src/assets/images/poses/smile.png +0 -0
  204. package/projects/facecog-liveness-verification-test/src/assets/images/poses/tilt_left.png +0 -0
  205. package/projects/facecog-liveness-verification-test/src/assets/images/poses/tilt_right.png +0 -0
  206. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_chin_left.jpg +0 -0
  207. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_left_cheek.jpeg +0 -0
  208. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_nose_right.png +0 -0
  209. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_right_cheek.jpeg +0 -0
  210. package/projects/facecog-liveness-verification-test/src/assets/images/poses/turn_left.png +0 -0
  211. package/projects/facecog-liveness-verification-test/src/assets/images/poses/turn_right.png +0 -0
  212. package/projects/facecog-liveness-verification-test/src/assets/images/poses/wink.jpeg +0 -0
  213. package/projects/facecog-liveness-verification-test/src/assets/images/reference-pose.jpg +0 -0
  214. package/projects/facecog-liveness-verification-test/src/assets/shapes.svg +1 -0
  215. package/projects/facecog-liveness-verification-test/src/environments/environment.prod.ts +4 -0
  216. package/projects/facecog-liveness-verification-test/src/environments/environment.ts +17 -0
  217. package/projects/facecog-liveness-verification-test/src/global.scss +288 -0
  218. package/projects/facecog-liveness-verification-test/src/index.html +31 -0
  219. package/projects/facecog-liveness-verification-test/src/main.ts +6 -0
  220. package/projects/facecog-liveness-verification-test/src/polyfills.ts +55 -0
  221. package/projects/facecog-liveness-verification-test/src/theme/nextsapien-theme.scss +174 -0
  222. package/projects/facecog-liveness-verification-test/src/theme/variables.scss +2 -0
  223. package/projects/facecog-liveness-verification-test/src/zone-flags.ts +6 -0
  224. package/projects/facecog-liveness-verification-test/tsconfig.app.json +15 -0
  225. package/projects/facecog-liveness-verification-test/tsconfig.spec.json +14 -0
  226. package/setup-jest.ts +118 -0
  227. package/tsconfig.json +41 -0
  228. package/tsconfig.spec.json +15 -0
  229. package/vercel.json +24 -0
@@ -0,0 +1,524 @@
1
+ import { Component, OnInit, OnDestroy, EventEmitter, Output, Input, ViewChild, ElementRef, Optional, Inject, NgZone, signal, computed, ChangeDetectionStrategy } from '@angular/core';
2
+ import { IonicModule } from '@ionic/angular';
3
+ import { CommonModule } from '@angular/common';
4
+
5
+ import { VideoRecorderService } from '../../services/video-recorder.service';
6
+ import { PoseMatchingService } from '../../services/pose-detection/pose-matching.service';
7
+ import { LivenessConfigService } from '../../services/liveness-config.service';
8
+ import { ICameraProvider, CAMERA_PROVIDER, BrightnessData } from '../../interfaces/camera-provider.interface';
9
+ import { ReferencePose } from '../../services/pose-detection/reference-pose.service';
10
+ import { SelectedPoseInfo } from '../../services/pose-selection.service';
11
+ import { PoseDefinition } from '../../interfaces/pose-definition.interface';
12
+
13
+ @Component({
14
+ selector: 'lib-live-preview',
15
+ standalone: true,
16
+ imports: [CommonModule, IonicModule],
17
+ templateUrl: './live-preview.component.html',
18
+ styleUrls: ['./live-preview.component.scss'],
19
+ changeDetection: ChangeDetectionStrategy.OnPush
20
+ })
21
+ export class LivePreviewComponent implements OnInit, OnDestroy {
22
+ @ViewChild('videoElement', { static: false }) videoElement!: ElementRef<HTMLVideoElement>;
23
+ @ViewChild('canvasOverlay', { static: false }) canvasOverlay!: ElementRef<HTMLCanvasElement>;
24
+ @Input() exampleImageUrl?: string;
25
+ @Input() exampleImageBase64?: string;
26
+ @Input() referencePose?: ReferencePose;
27
+ @Input() selectedPose?: SelectedPoseInfo;
28
+ @Input() hideCancel = false;
29
+ @Output() captureComplete = new EventEmitter<{ frames: string[], videoBlob?: Blob }>();
30
+ @Output() cancelled = new EventEmitter<void>();
31
+
32
+ readonly stream = signal<MediaStream | null>(null);
33
+ readonly matchProgress = signal(0);
34
+ readonly statusMessage = signal('Position yourself in the frame...');
35
+ readonly isMatching = signal(false);
36
+ private matchingInterval: any;
37
+ private capturedFrames: string[] = [];
38
+ private canvasAnimationFrame: number | null = null;
39
+
40
+ readonly brightnessLevel = signal(128);
41
+ readonly isLowLight = signal(false);
42
+ readonly isTooLight = signal(false);
43
+ readonly lightingWarning = signal('');
44
+ private brightnessMonitoringId: number | null = null;
45
+
46
+ private readonly circumference = 1515;
47
+
48
+ readonly progressOffset = computed(() => {
49
+ const progress = this.matchProgress() / 100;
50
+ return this.circumference * (1 - progress);
51
+ });
52
+
53
+ readonly showPoseOverlay = signal(false);
54
+ readonly currentPoseAction = signal<string>('smile');
55
+ readonly currentPoseDescription = signal<string>('Smile naturally');
56
+
57
+ readonly cameraError = signal<'none' | 'not-found' | 'not-readable' | 'denied' | 'generic'>('none');
58
+
59
+ readonly showFollowDot = signal(false);
60
+ readonly dotX = signal(0);
61
+ readonly dotY = signal(0);
62
+ private dotAnimationInterval: any = null;
63
+ private dotPositions = [
64
+ { x: 0.5, y: 0.2 },
65
+ { x: 0.8, y: 0.3 },
66
+ { x: 0.8, y: 0.7 },
67
+ { x: 0.5, y: 0.8 },
68
+ { x: 0.2, y: 0.7 },
69
+ { x: 0.2, y: 0.3 },
70
+ ];
71
+ private currentDotIndex = 0;
72
+
73
+ constructor(
74
+ private videoRecorder: VideoRecorderService,
75
+ private poseMatching: PoseMatchingService,
76
+ private configService: LivenessConfigService,
77
+ private ngZone: NgZone,
78
+ @Optional() @Inject(CAMERA_PROVIDER) private cameraProvider?: ICameraProvider
79
+ ) {}
80
+
81
+ async ngOnInit() {
82
+ try {
83
+ this.statusMessage.set('Loading face detection models...');
84
+ await this.poseMatching.loadModels();
85
+
86
+ const config = this.configService.getConfig();
87
+ if (config.exampleImageUrl) {
88
+ try {
89
+ this.statusMessage.set('Loading reference image...');
90
+ await this.poseMatching.loadReferenceImage(config.exampleImageUrl);
91
+ console.log('Reference image loaded successfully');
92
+ } catch (refError) {
93
+ console.warn('Failed to load reference image, continuing without pose matching:', refError);
94
+ }
95
+ }
96
+
97
+ await this.startCamera();
98
+ } catch (error) {
99
+ console.error('Initialization error:', error);
100
+ this.statusMessage.set('Failed to initialize. Please refresh the page.');
101
+ }
102
+ }
103
+
104
+ async startCamera() {
105
+ try {
106
+ this.statusMessage.set('Requesting camera access...');
107
+ const mediaStream = await navigator.mediaDevices.getUserMedia({
108
+ video: { facingMode: 'user', width: { ideal: 1280 }, height: { ideal: 720 } },
109
+ audio: false
110
+ });
111
+ this.stream.set(mediaStream);
112
+
113
+ setTimeout(() => {
114
+ if (this.videoElement?.nativeElement) {
115
+ this.videoElement.nativeElement.srcObject = mediaStream;
116
+ }
117
+ }, 100);
118
+
119
+ const config = this.configService.getConfig();
120
+ if (config.enableVideoRecording) {
121
+ try {
122
+ await this.videoRecorder.startRecording(mediaStream);
123
+ } catch (recordError) {
124
+ console.warn('Video recording failed, continuing without recording:', recordError);
125
+ }
126
+ }
127
+
128
+ setTimeout(() => {
129
+ if (this.videoElement?.nativeElement) {
130
+ this.startBrightnessMonitoring();
131
+ }
132
+ }, 500);
133
+
134
+ this.statusMessage.set('Position yourself in the frame...');
135
+ this.startPoseMatching();
136
+ } catch (error: any) {
137
+ console.error('Failed to start camera:', error);
138
+
139
+ if (error.name === 'NotAllowedError') {
140
+ this.cameraError.set('denied');
141
+ this.statusMessage.set('Camera access denied. Please grant permission and try again.');
142
+ } else if (error.name === 'NotFoundError') {
143
+ this.cameraError.set('not-found');
144
+ this.statusMessage.set('No camera found. Please connect a camera and try again.');
145
+ } else if (error.name === 'NotReadableError') {
146
+ this.cameraError.set('not-readable');
147
+ this.statusMessage.set('Camera is already in use by another application.');
148
+ } else {
149
+ this.cameraError.set('generic');
150
+ this.statusMessage.set('Camera error. Please check permissions and try again.');
151
+ }
152
+ }
153
+ }
154
+
155
+ async retryCamera(): Promise<void> {
156
+ this.cameraError.set('none');
157
+ this.statusMessage.set('Retrying camera access...');
158
+ await this.startCamera();
159
+ }
160
+
161
+ startPoseMatching() {
162
+ this.poseMatching.resetActionState();
163
+ this.showPoseOverlay.set(true);
164
+
165
+ if (this.selectedPose) {
166
+ this.currentPoseAction.set(this.getPoseAction(this.selectedPose.pose));
167
+ this.currentPoseDescription.set(this.selectedPose.pose.description);
168
+
169
+ console.log('[Live Preview] Starting single pose detection');
170
+ console.log('[Live Preview] Pose:', this.selectedPose.pose.name);
171
+ console.log('[Live Preview] Category:', this.selectedPose.pose.category);
172
+ console.log('[Live Preview] Description:', this.currentPoseDescription());
173
+ console.log('[Live Preview] Action:', this.currentPoseAction());
174
+
175
+ if (this.currentPoseAction() === 'follow-dot') {
176
+ this.startDotAnimation();
177
+ }
178
+
179
+ if (this.selectedPose.pose.poseKeypoints && this.selectedPose.pose.poseKeypoints.length > 0) {
180
+ console.log('[Live Preview] Setting static pose keypoints for automatic detection');
181
+ this.poseMatching.setStaticPoseKeypoints(this.selectedPose.pose.poseKeypoints);
182
+ this.statusMessage.set(`Position yourself to match the pose: ${this.selectedPose.pose.name}`);
183
+ } else {
184
+ console.log('[Live Preview] No keypoints available - using fallback detection');
185
+ this.poseMatching.setStaticPoseKeypoints(null);
186
+ this.statusMessage.set(`Get ready: ${this.currentPoseDescription()}`);
187
+ }
188
+ } else if (this.referencePose) {
189
+ this.currentPoseAction.set('custom-pose');
190
+ this.currentPoseDescription.set(this.referencePose.poseDescription);
191
+ console.log('[Live Preview] Starting custom pose detection');
192
+ console.log('[Live Preview] Description:', this.currentPoseDescription());
193
+ this.statusMessage.set(`Get ready: ${this.currentPoseDescription()}`);
194
+ } else {
195
+ this.currentPoseAction.set('smile');
196
+ this.currentPoseDescription.set('Smile naturally');
197
+ console.log('[Live Preview] Starting default pose detection (smile)');
198
+ this.statusMessage.set('Get ready: Smile naturally');
199
+ }
200
+
201
+ this.matchingInterval = setInterval(async () => {
202
+ if (!this.videoElement?.nativeElement || !this.stream()) {
203
+ console.warn('[Live Preview] Video element or stream not available');
204
+ return;
205
+ }
206
+
207
+ try {
208
+ const result = await this.poseMatching.detectAction(
209
+ this.videoElement.nativeElement,
210
+ this.currentPoseAction() as any
211
+ );
212
+
213
+ this.statusMessage.set(result.message);
214
+ this.matchProgress.set(result.progress * 100);
215
+
216
+ console.log(`[Live Preview] ${this.currentPoseAction()} - Progress: ${(result.progress * 100).toFixed(1)}%, Completed: ${result.completed}`);
217
+
218
+ if (result.completed) {
219
+ console.log(`[Live Preview] ✓ Pose complete! ${this.currentPoseDescription()} detected - capturing...`);
220
+ this.statusMessage.set('Perfect! Capturing...');
221
+ await this.captureFrames();
222
+ return;
223
+ }
224
+ } catch (error) {
225
+ console.error(`[Live Preview] ${this.currentPoseAction()} detection error:`, error);
226
+ this.statusMessage.set('Unable to detect pose. Please ensure good lighting.');
227
+ }
228
+ }, 200);
229
+ }
230
+
231
+ private getPoseAction(pose: PoseDefinition): string {
232
+ if (pose.poseKeypoints && pose.poseKeypoints.length > 0) {
233
+ console.log(`[Live Preview] Pose "${pose.name}" has static keypoints - using automatic detection`);
234
+ return 'custom-pose';
235
+ }
236
+
237
+ const poseName = pose.name.toLowerCase();
238
+
239
+ if (poseName.includes('palm')) {
240
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
241
+ this.poseMatching.setExpectedGesture('palm', handedness);
242
+ console.log(`[Live Preview] Palm gesture with handedness: ${handedness}`);
243
+ return 'hand-gesture';
244
+ }
245
+ if (poseName.includes('thumbs up') || poseName.includes('thumbs-up')) {
246
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
247
+ this.poseMatching.setExpectedGesture('thumbs_up', handedness);
248
+ console.log(`[Live Preview] Thumbs up gesture with handedness: ${handedness}`);
249
+ return 'hand-gesture';
250
+ }
251
+ if (poseName.includes('peace')) {
252
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
253
+ this.poseMatching.setExpectedGesture('peace', handedness);
254
+ console.log(`[Live Preview] Peace gesture with handedness: ${handedness}`);
255
+ return 'hand-gesture';
256
+ }
257
+ if (poseName.includes('ok sign') || poseName.includes('ok-sign')) {
258
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
259
+ this.poseMatching.setExpectedGesture('ok', handedness);
260
+ console.log(`[Live Preview] OK gesture with handedness: ${handedness}`);
261
+ return 'hand-gesture';
262
+ }
263
+ if (poseName.includes('fist')) {
264
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
265
+ this.poseMatching.setExpectedGesture('fist', handedness);
266
+ console.log(`[Live Preview] Fist gesture with handedness: ${handedness}`);
267
+ return 'hand-gesture';
268
+ }
269
+ if (poseName.includes('three fingers') || poseName.includes('three-fingers')) {
270
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
271
+ this.poseMatching.setExpectedGesture('three', handedness);
272
+ console.log(`[Live Preview] Three fingers gesture with handedness: ${handedness}`);
273
+ return 'hand-gesture';
274
+ }
275
+ if (poseName.includes('five fingers') || poseName.includes('five-fingers')) {
276
+ const handedness = poseName.includes('right') ? 'Right' : poseName.includes('left') ? 'Left' : 'Any';
277
+ this.poseMatching.setExpectedGesture('palm', handedness);
278
+ console.log(`[Live Preview] Five fingers (palm) gesture with handedness: ${handedness}`);
279
+ return 'hand-gesture';
280
+ }
281
+
282
+ if (poseName.includes('smile')) return 'smile';
283
+ if (poseName.includes('open') && poseName.includes('mouth')) return 'open-mouth';
284
+ if (poseName.includes('raise') && poseName.includes('eyebrow')) return 'raise-eyebrows';
285
+ if (poseName.includes('blink') && poseName.includes('twice')) return 'blink-twice';
286
+ if (poseName.includes('blink')) return 'blink';
287
+ if (poseName.includes('wink')) return 'wink';
288
+ if (poseName.includes('follow') && poseName.includes('dot')) return 'follow-dot';
289
+ if (poseName.includes('speak') && poseName.includes('phrase')) return 'speak-phrase';
290
+ if (poseName.includes('look') && poseName.includes('up')) return 'look-up';
291
+ if (poseName.includes('look') && poseName.includes('down')) return 'look-down';
292
+ if (poseName.includes('turn') && poseName.includes('left')) return 'turn-left';
293
+ if (poseName.includes('turn') && poseName.includes('right')) return 'turn-right';
294
+ if (poseName.includes('tilt') && poseName.includes('left')) return 'tilt-left';
295
+ if (poseName.includes('tilt') && poseName.includes('right')) return 'tilt-right';
296
+ if (poseName.includes('nod')) return 'nod';
297
+ if (poseName.includes('shake') && poseName.includes('head')) return 'shake-head';
298
+ if (poseName.includes('rotate') && poseName.includes('face')) return 'rotate-face';
299
+ if (poseName.includes('straight') || poseName.includes('center')) return 'face-center';
300
+
301
+ if (poseName.includes('wave')) {
302
+ console.log(`[Live Preview] "${pose.name}" will use Wave detection`);
303
+ return 'wave';
304
+ }
305
+ if (poseName.includes('clap')) {
306
+ console.log(`[Live Preview] "${pose.name}" will use Clap detection`);
307
+ return 'clap';
308
+ }
309
+ if (poseName.includes('cross') && poseName.includes('arms')) {
310
+ console.log(`[Live Preview] "${pose.name}" will use Cross Arms detection`);
311
+ return 'cross-arms';
312
+ }
313
+ if (poseName.includes('point')) {
314
+ console.log(`[Live Preview] "${pose.name}" will use Point detection`);
315
+ return 'point';
316
+ }
317
+
318
+ if (poseName.includes('touch') || poseName.includes('cover') || poseName.includes('frame')) {
319
+ console.log(`[Live Preview] "${pose.name}" will use Combined Pose detection`);
320
+ const poseType = pose.name.toLowerCase().replace(/ /g, '-');
321
+ this.poseMatching.setCombinedPoseType(poseType);
322
+ return 'combined-pose';
323
+ }
324
+ if (poseName.includes('hand') && poseName.includes('ear')) {
325
+ console.log(`[Live Preview] "${pose.name}" will use Combined Pose detection`);
326
+ this.poseMatching.setCombinedPoseType('hand-ear-to-shoulder');
327
+ return 'combined-pose';
328
+ }
329
+
330
+ if (pose.category === 'face') return 'smile';
331
+ if (pose.category === 'head') return 'face-center';
332
+
333
+ console.warn(`[Live Preview] Pose "${pose.name}" has no detection strategy - falling back to custom pose`);
334
+ return 'custom-pose';
335
+ }
336
+
337
+
338
+ async captureFrames() {
339
+ clearInterval(this.matchingInterval);
340
+ this.stopDotAnimation();
341
+ this.statusMessage.set('Perfect! Capturing...');
342
+ this.isMatching.set(true);
343
+
344
+ const config = this.configService.getConfig();
345
+ const frameCount = config.captureFrameCount || 5;
346
+
347
+ for (let i = 0; i < frameCount; i++) {
348
+ await new Promise(resolve => setTimeout(resolve, 100));
349
+ const frame = this.poseMatching.frameToBase64(this.videoElement.nativeElement);
350
+ this.capturedFrames.push(frame);
351
+ }
352
+
353
+ let videoBlob: Blob | undefined;
354
+ if (config.enableVideoRecording && this.videoRecorder.isRecording()) {
355
+ const recording = await this.videoRecorder.stopRecording();
356
+ videoBlob = recording.blob;
357
+ }
358
+
359
+ this.ngZone.run(() => {
360
+ this.captureComplete.emit({
361
+ frames: this.capturedFrames,
362
+ videoBlob
363
+ });
364
+ });
365
+ }
366
+
367
+ manualCapture() {
368
+ this.captureFrames();
369
+ }
370
+
371
+ onCancel() {
372
+ this.cancelled.emit();
373
+ }
374
+
375
+ private startBrightnessMonitoring() {
376
+ if (!this.videoElement?.nativeElement) {
377
+ console.warn('[Brightness] Video element not available');
378
+ return;
379
+ }
380
+
381
+ console.log('[Brightness] Starting brightness monitoring');
382
+
383
+ if (this.cameraProvider?.startBrightnessMonitoring) {
384
+ this.brightnessMonitoringId = this.cameraProvider.startBrightnessMonitoring(
385
+ this.videoElement.nativeElement,
386
+ (data) => this.handleBrightnessData(data),
387
+ 1000
388
+ );
389
+ } else {
390
+ this.brightnessMonitoringId = window.setInterval(() => {
391
+ const data = this.analyzeBrightness(this.videoElement.nativeElement);
392
+ this.handleBrightnessData(data);
393
+ }, 1000);
394
+ }
395
+ }
396
+
397
+ private handleBrightnessData(data: BrightnessData) {
398
+ this.brightnessLevel.set(data.brightness);
399
+ this.isLowLight.set(data.isLowLight);
400
+ this.isTooLight.set(data.isTooLight);
401
+
402
+ if (data.isLowLight) {
403
+ this.lightingWarning.set('Low light detected. Please move to a brighter area.');
404
+ console.log(`[Brightness] Low light: ${data.brightness.toFixed(1)}/255`);
405
+ } else if (data.isTooLight) {
406
+ this.lightingWarning.set('Too bright. Please avoid direct light sources.');
407
+ console.log(`[Brightness] Too bright: ${data.brightness.toFixed(1)}/255`);
408
+ } else {
409
+ this.lightingWarning.set('');
410
+ }
411
+ }
412
+
413
+ private analyzeBrightness(videoElement: HTMLVideoElement): BrightnessData {
414
+ const canvas = document.createElement('canvas');
415
+ const width = videoElement.videoWidth;
416
+ const height = videoElement.videoHeight;
417
+
418
+ const sampleWidth = Math.min(width, 320);
419
+ const sampleHeight = Math.min(height, 240);
420
+
421
+ canvas.width = sampleWidth;
422
+ canvas.height = sampleHeight;
423
+
424
+ const context = canvas.getContext('2d');
425
+ if (!context) {
426
+ console.warn('Could not get canvas context for brightness analysis');
427
+ return { brightness: 128, isLowLight: false, isTooLight: false };
428
+ }
429
+
430
+ context.drawImage(videoElement, 0, 0, sampleWidth, sampleHeight);
431
+
432
+ try {
433
+ const imageData = context.getImageData(0, 0, sampleWidth, sampleHeight);
434
+ const data = imageData.data;
435
+
436
+ let totalBrightness = 0;
437
+ const pixelCount = data.length / 4;
438
+
439
+ for (let i = 0; i < data.length; i += 4) {
440
+ const r = data[i];
441
+ const g = data[i + 1];
442
+ const b = data[i + 2];
443
+ const brightness = (0.299 * r + 0.587 * g + 0.114 * b);
444
+ totalBrightness += brightness;
445
+ }
446
+
447
+ const averageBrightness = totalBrightness / pixelCount;
448
+
449
+ const LOW_LIGHT_THRESHOLD = 60;
450
+ const TOO_BRIGHT_THRESHOLD = 200;
451
+
452
+ return {
453
+ brightness: averageBrightness,
454
+ isLowLight: averageBrightness < LOW_LIGHT_THRESHOLD,
455
+ isTooLight: averageBrightness > TOO_BRIGHT_THRESHOLD
456
+ };
457
+ } catch (error) {
458
+ console.warn('Error analyzing brightness:', error);
459
+ return { brightness: 128, isLowLight: false, isTooLight: false };
460
+ }
461
+ }
462
+
463
+ private stopBrightnessMonitoring() {
464
+ if (this.brightnessMonitoringId !== null) {
465
+ if (this.cameraProvider?.stopBrightnessMonitoring) {
466
+ this.cameraProvider.stopBrightnessMonitoring(this.brightnessMonitoringId);
467
+ } else {
468
+ clearInterval(this.brightnessMonitoringId);
469
+ }
470
+ this.brightnessMonitoringId = null;
471
+ console.log('[Brightness] Stopped brightness monitoring');
472
+ }
473
+ }
474
+
475
+ private startDotAnimation() {
476
+ this.showFollowDot.set(true);
477
+ this.currentDotIndex = 0;
478
+
479
+ const viewportWidth = window.innerWidth;
480
+ const viewportHeight = window.innerHeight;
481
+
482
+ this.updateDotPosition(viewportWidth, viewportHeight);
483
+
484
+ this.dotAnimationInterval = setInterval(() => {
485
+ this.currentDotIndex = (this.currentDotIndex + 1) % this.dotPositions.length;
486
+ this.updateDotPosition(viewportWidth, viewportHeight);
487
+ console.log(`[Follow Dot] Moving to position ${this.currentDotIndex}`);
488
+ }, 1500);
489
+
490
+ console.log('[Follow Dot] Animation started');
491
+ }
492
+
493
+ private updateDotPosition(viewportWidth: number, viewportHeight: number) {
494
+ const pos = this.dotPositions[this.currentDotIndex];
495
+ this.dotX.set(pos.x * viewportWidth);
496
+ this.dotY.set(pos.y * viewportHeight);
497
+ }
498
+
499
+ private stopDotAnimation() {
500
+ if (this.dotAnimationInterval) {
501
+ clearInterval(this.dotAnimationInterval);
502
+ this.dotAnimationInterval = null;
503
+ }
504
+ this.showFollowDot.set(false);
505
+ console.log('[Follow Dot] Animation stopped');
506
+ }
507
+
508
+ ngOnDestroy() {
509
+ if (this.matchingInterval) {
510
+ clearInterval(this.matchingInterval);
511
+ }
512
+ if (this.canvasAnimationFrame) {
513
+ cancelAnimationFrame(this.canvasAnimationFrame);
514
+ }
515
+ this.stopBrightnessMonitoring();
516
+ this.stopDotAnimation();
517
+ const currentStream = this.stream();
518
+ if (currentStream) {
519
+ currentStream.getTracks().forEach(track => track.stop());
520
+ }
521
+ this.videoRecorder.cleanup();
522
+ this.poseMatching.cleanup();
523
+ }
524
+ }
@@ -0,0 +1,73 @@
1
+ <div class="liveness-flow-container">
2
+ <lib-intro
3
+ *ngIf="currentStep() === 'intro'"
4
+ [exampleImageUrl]="config.exampleImageUrl"
5
+ [exampleImageBase64]="config.exampleImageBase64"
6
+ [poseSpecificMode]="poseSpecificMode"
7
+ (startClicked)="onStartClicked()"
8
+ (cancelClicked)="onCancel()"
9
+ (referencePoseUploaded)="onReferencePoseUploaded($event)"
10
+ (poseSelected)="onPoseSelected($event)"
11
+ (awsFaceLivenessToggled)="onAwsFaceLivenessToggled($event)">
12
+ </lib-intro>
13
+
14
+ <lib-camera-permission
15
+ *ngIf="currentStep() === 'permission'"
16
+ [hideCancel]="poseSpecificMode"
17
+ [poseSpecificMode]="poseSpecificMode"
18
+ (permissionGranted)="onPermissionGranted()"
19
+ (permissionDenied)="onPermissionDenied()">
20
+ </lib-camera-permission>
21
+
22
+ <lib-live-preview
23
+ *ngIf="currentStep() === 'preview'"
24
+ [exampleImageUrl]="config.exampleImageUrl"
25
+ [exampleImageBase64]="config.exampleImageBase64"
26
+ [referencePose]="referencePose"
27
+ [selectedPose]="selectedPose"
28
+ [hideCancel]="poseSpecificMode"
29
+ (captureComplete)="onCaptureComplete($event)"
30
+ (cancelled)="onCancel()">
31
+ </lib-live-preview>
32
+
33
+ <facecog-facetec-scan
34
+ *ngIf="currentStep() === 'facetec'"
35
+ [sessionId]="verificationSessionId"
36
+ [deviceKey]="deviceKey"
37
+ [autoStart]="true"
38
+ (scanComplete)="onFaceTecScanComplete($event)"
39
+ (scanCancelled)="onFaceTecScanCancelled()">
40
+ </facecog-facetec-scan>
41
+
42
+ <!-- AWS Face Liveness: Dynamic component via injection token OR direct import fallback -->
43
+ <ng-container *ngIf="currentStep() === 'aws-liveness'">
44
+ <!-- Container for dynamically injected component -->
45
+ <ng-template #awsLivenessContainer></ng-template>
46
+
47
+ <!-- Fallback to direct component if no injected component -->
48
+ <facecog-aws-face-liveness
49
+ *ngIf="!awsFaceLivenessComponent"
50
+ [region]="awsRegion"
51
+ [autoStart]="true"
52
+ [showCancelButton]="true"
53
+ (scanComplete)="onAwsFaceLivenessComplete($event)"
54
+ (scanCancelled)="onAwsFaceLivenessCancelled()">
55
+ </facecog-aws-face-liveness>
56
+ </ng-container>
57
+
58
+ <lib-processing
59
+ *ngIf="currentStep() === 'processing'"
60
+ [capturedImage]="capturedFrames[0]"
61
+ [progress]="processingProgress()">
62
+ </lib-processing>
63
+
64
+ <lib-verification-result
65
+ *ngIf="currentStep() === 'result' && result()"
66
+ [result]="result()!"
67
+ [poseSpecificMode]="poseSpecificMode"
68
+ (doneClicked)="onDone()"
69
+ (retryClicked)="onRetry()"
70
+ (autoRetry)="onAutoRetry()"
71
+ (autoComplete)="onAutoComplete($event)">
72
+ </lib-verification-result>
73
+ </div>
@@ -0,0 +1,19 @@
1
+ :host {
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+ height: 100%;
6
+ min-height: 0;
7
+ background: var(--ion-background-color, #fff);
8
+ }
9
+
10
+ .liveness-flow-container {
11
+ display: flex;
12
+ flex-direction: column;
13
+ width: 100%;
14
+ flex: 1;
15
+ min-height: 0;
16
+ overflow-y: auto;
17
+ position: relative;
18
+ background: var(--ion-background-color, #fff);
19
+ }