Browse Source

Face Module Added

Anand Ayyappan 3 months ago
parent
commit
4021d2f4f4
74 changed files with 1180 additions and 406 deletions
  1. 4 2
      angular.json
  2. BIN
      assets/models/age_gender_model-shard1
  3. 0 0
      assets/models/age_gender_model-weights_manifest.json
  4. BIN
      assets/models/face_expression_model-shard1
  5. 0 0
      assets/models/face_expression_model-weights_manifest.json
  6. BIN
      assets/models/face_landmark_68_model-shard1
  7. 0 0
      assets/models/face_landmark_68_model-weights_manifest.json
  8. BIN
      assets/models/face_landmark_68_tiny_model-shard1
  9. 0 0
      assets/models/face_landmark_68_tiny_model-weights_manifest.json
  10. BIN
      assets/models/face_recognition_model-shard1
  11. 0 0
      assets/models/face_recognition_model-shard2
  12. 0 0
      assets/models/face_recognition_model-weights_manifest.json
  13. BIN
      assets/models/mtcnn_model-shard1
  14. 0 0
      assets/models/mtcnn_model-weights_manifest.json
  15. BIN
      assets/models/ssd_mobilenetv1_model-shard1
  16. 0 0
      assets/models/ssd_mobilenetv1_model-shard2
  17. 0 0
      assets/models/ssd_mobilenetv1_model-weights_manifest.json
  18. BIN
      assets/models/tiny_face_detector_model-shard1
  19. 0 0
      assets/models/tiny_face_detector_model-weights_manifest.json
  20. 277 206
      package-lock.json
  21. 3 0
      package.json
  22. BIN
      public/assets/models/age_gender_model-shard1
  23. 0 0
      public/assets/models/age_gender_model-weights_manifest.json
  24. BIN
      public/assets/models/face_expression_model-shard1
  25. 0 0
      public/assets/models/face_expression_model-weights_manifest.json
  26. BIN
      public/assets/models/face_landmark_68_model-shard1
  27. 0 0
      public/assets/models/face_landmark_68_model-weights_manifest.json
  28. BIN
      public/assets/models/face_landmark_68_tiny_model-shard1
  29. 0 0
      public/assets/models/face_landmark_68_tiny_model-weights_manifest.json
  30. BIN
      public/assets/models/face_recognition_model-shard1
  31. 0 0
      public/assets/models/face_recognition_model-shard2
  32. 0 0
      public/assets/models/face_recognition_model-weights_manifest.json
  33. BIN
      public/assets/models/mtcnn_model-shard1
  34. 0 0
      public/assets/models/mtcnn_model-weights_manifest.json
  35. BIN
      public/assets/models/ssd_mobilenetv1_model-shard1
  36. 0 0
      public/assets/models/ssd_mobilenetv1_model-shard2
  37. 0 0
      public/assets/models/ssd_mobilenetv1_model-weights_manifest.json
  38. BIN
      public/assets/models/tiny_face_detector_model-shard1
  39. 0 0
      public/assets/models/tiny_face_detector_model-weights_manifest.json
  40. 0 191
      src/app/app.component.html
  41. 7 3
      src/app/app.component.ts
  42. 6 1
      src/app/app.config.ts
  43. 23 1
      src/app/app.routes.ts
  44. 17 0
      src/app/auth/auth.guard.spec.ts
  45. 13 0
      src/app/auth/auth.guard.ts
  46. 16 0
      src/app/auth/auth.service.spec.ts
  47. 29 0
      src/app/auth/auth.service.ts
  48. 17 0
      src/app/interceptors/error.interceptor.spec.ts
  49. 25 0
      src/app/interceptors/error.interceptor.ts
  50. 2 0
      src/app/interceptors/error.ts
  51. 3 0
      src/app/pages/dashboard/dashboard.component.css
  52. 203 0
      src/app/pages/dashboard/dashboard.component.html
  53. 23 0
      src/app/pages/dashboard/dashboard.component.spec.ts
  54. 18 0
      src/app/pages/dashboard/dashboard.component.ts
  55. 8 0
      src/app/pages/face/face.component.css
  56. 87 0
      src/app/pages/face/face.component.html
  57. 23 0
      src/app/pages/face/face.component.spec.ts
  58. 112 0
      src/app/pages/face/face.component.ts
  59. 0 0
      src/app/pages/header/header.component.css
  60. 38 0
      src/app/pages/header/header.component.html
  61. 23 0
      src/app/pages/header/header.component.spec.ts
  62. 19 0
      src/app/pages/header/header.component.ts
  63. 0 0
      src/app/pages/login/login.component.css
  64. 29 0
      src/app/pages/login/login.component.html
  65. 23 0
      src/app/pages/login/login.component.spec.ts
  66. 33 0
      src/app/pages/login/login.component.ts
  67. 0 0
      src/app/pages/register/register.component.css
  68. 1 0
      src/app/pages/register/register.component.html
  69. 23 0
      src/app/pages/register/register.component.spec.ts
  70. 12 0
      src/app/pages/register/register.component.ts
  71. 16 0
      src/app/services/error-handler.service.spec.ts
  72. 40 0
      src/app/services/error-handler.service.ts
  73. 4 2
      src/index.html
  74. 3 0
      src/styles.css

+ 4 - 2
angular.json

@@ -29,7 +29,8 @@
             "styles": [
             "styles": [
               "src/styles.css"
               "src/styles.css"
             ],
             ],
-            "scripts": []
+            "scripts": [
+            ]
           },
           },
           "configurations": {
           "configurations": {
             "production": {
             "production": {
@@ -87,7 +88,8 @@
             "styles": [
             "styles": [
               "src/styles.css"
               "src/styles.css"
             ],
             ],
-            "scripts": []
+            "scripts": [
+            ]
           }
           }
         }
         }
       }
       }

BIN
assets/models/age_gender_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/age_gender_model-weights_manifest.json


BIN
assets/models/face_expression_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/face_expression_model-weights_manifest.json


BIN
assets/models/face_landmark_68_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/face_landmark_68_model-weights_manifest.json


BIN
assets/models/face_landmark_68_tiny_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/face_landmark_68_tiny_model-weights_manifest.json


BIN
assets/models/face_recognition_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/face_recognition_model-shard2


File diff suppressed because it is too large
+ 0 - 0
assets/models/face_recognition_model-weights_manifest.json


BIN
assets/models/mtcnn_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/mtcnn_model-weights_manifest.json


BIN
assets/models/ssd_mobilenetv1_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/ssd_mobilenetv1_model-shard2


File diff suppressed because it is too large
+ 0 - 0
assets/models/ssd_mobilenetv1_model-weights_manifest.json


BIN
assets/models/tiny_face_detector_model-shard1


File diff suppressed because it is too large
+ 0 - 0
assets/models/tiny_face_detector_model-weights_manifest.json


+ 277 - 206
package-lock.json

@@ -16,6 +16,9 @@
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/router": "^18.0.0",
         "@angular/router": "^18.0.0",
+        "@tensorflow/tfjs-core": "^4.22.0",
+        "bootstrap": "^5.3.3",
+        "face-api.js": "^0.22.2",
         "rxjs": "~7.8.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.14.3"
         "zone.js": "~0.14.3"
@@ -450,6 +453,36 @@
         "typescript": ">=5.4 <5.6"
         "typescript": ">=5.4 <5.6"
       }
       }
     },
     },
+    "node_modules/@angular/compiler-cli/node_modules/chokidar": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
+      "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/@angular/compiler-cli/node_modules/readdirp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
+      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/@angular/core": {
     "node_modules/@angular/core": {
       "version": "18.2.9",
       "version": "18.2.9",
       "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.9.tgz",
       "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.9.tgz",
@@ -3896,6 +3929,17 @@
         "node": ">=14"
         "node": ">=14"
       }
       }
     },
     },
+    "node_modules/@popperjs/core": {
+      "version": "2.11.8",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+      "license": "MIT",
+      "peer": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
     "node_modules/@rollup/rollup-android-arm-eabi": {
     "node_modules/@rollup/rollup-android-arm-eabi": {
       "version": "4.22.4",
       "version": "4.22.4",
       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
@@ -4237,6 +4281,24 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/@tensorflow/tfjs-core": {
+      "version": "4.22.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-4.22.0.tgz",
+      "integrity": "sha512-LEkOyzbknKFoWUwfkr59vSB68DMJ4cjwwHgicXN0DUi3a0Vh1Er3JQqCI1Hl86GGZQvY8ezVrtDIvqR1ZFW55A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/long": "^4.0.1",
+        "@types/offscreencanvas": "~2019.7.0",
+        "@types/seedrandom": "^2.4.28",
+        "@webgpu/types": "0.1.38",
+        "long": "4.0.0",
+        "node-fetch": "~2.6.1",
+        "seedrandom": "^3.0.5"
+      },
+      "engines": {
+        "yarn": ">= 1.3.2"
+      }
+    },
     "node_modules/@tufjs/canonical-json": {
     "node_modules/@tufjs/canonical-json": {
       "version": "2.0.0",
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
@@ -4423,6 +4485,12 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/@types/long": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
+      "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
+      "license": "MIT"
+    },
     "node_modules/@types/mime": {
     "node_modules/@types/mime": {
       "version": "1.3.5",
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
       "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@@ -4460,6 +4528,12 @@
         "@types/node": "*"
         "@types/node": "*"
       }
       }
     },
     },
+    "node_modules/@types/offscreencanvas": {
+      "version": "2019.7.3",
+      "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
+      "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==",
+      "license": "MIT"
+    },
     "node_modules/@types/qs": {
     "node_modules/@types/qs": {
       "version": "6.9.16",
       "version": "6.9.16",
       "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
       "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
@@ -4481,6 +4555,12 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/@types/seedrandom": {
+      "version": "2.4.34",
+      "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.34.tgz",
+      "integrity": "sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==",
+      "license": "MIT"
+    },
     "node_modules/@types/send": {
     "node_modules/@types/send": {
       "version": "0.17.4",
       "version": "0.17.4",
       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
@@ -4524,6 +4604,18 @@
         "@types/node": "*"
         "@types/node": "*"
       }
       }
     },
     },
+    "node_modules/@types/webgl-ext": {
+      "version": "0.0.30",
+      "resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz",
+      "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==",
+      "license": "MIT"
+    },
+    "node_modules/@types/webgl2": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.4.tgz",
+      "integrity": "sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==",
+      "license": "MIT"
+    },
     "node_modules/@types/wrap-ansi": {
     "node_modules/@types/wrap-ansi": {
       "version": "3.0.0",
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz",
@@ -4715,6 +4807,12 @@
         "@xtuc/long": "4.2.2"
         "@xtuc/long": "4.2.2"
       }
       }
     },
     },
+    "node_modules/@webgpu/types": {
+      "version": "0.1.38",
+      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.38.tgz",
+      "integrity": "sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==",
+      "license": "BSD-3-Clause"
+    },
     "node_modules/@xtuc/ieee754": {
     "node_modules/@xtuc/ieee754": {
       "version": "1.2.0",
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
       "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -5251,6 +5349,25 @@
       "dev": true,
       "dev": true,
       "license": "ISC"
       "license": "ISC"
     },
     },
+    "node_modules/bootstrap": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+      "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/twbs"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/bootstrap"
+        }
+      ],
+      "license": "MIT",
+      "peerDependencies": {
+        "@popperjs/core": "^2.11.8"
+      }
+    },
     "node_modules/brace-expansion": {
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -5520,19 +5637,41 @@
       "license": "MIT"
       "license": "MIT"
     },
     },
     "node_modules/chokidar": {
     "node_modules/chokidar": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
-      "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "readdirp": "^4.0.1"
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
       },
       },
       "engines": {
       "engines": {
-        "node": ">= 14.16.0"
+        "node": ">= 8.10.0"
       },
       },
       "funding": {
       "funding": {
         "url": "https://paulmillr.com/funding/"
         "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chokidar/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
       }
       }
     },
     },
     "node_modules/chownr": {
     "node_modules/chownr": {
@@ -6459,7 +6598,6 @@
       "version": "0.1.13",
       "version": "0.1.13",
       "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
       "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
       "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
       "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "optional": true,
       "optional": true,
       "dependencies": {
       "dependencies": {
@@ -6470,7 +6608,6 @@
       "version": "0.6.3",
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
       "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
       "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "optional": true,
       "optional": true,
       "dependencies": {
       "dependencies": {
@@ -6975,6 +7112,66 @@
         "node": ">=4"
         "node": ">=4"
       }
       }
     },
     },
+    "node_modules/face-api.js": {
+      "version": "0.22.2",
+      "resolved": "https://registry.npmjs.org/face-api.js/-/face-api.js-0.22.2.tgz",
+      "integrity": "sha512-9Bbv/yaBRTKCXjiDqzryeKhYxmgSjJ7ukvOvEBy6krA0Ah/vNBlsf7iBNfJljWiPA8Tys1/MnB3lyP2Hfmsuyw==",
+      "license": "MIT",
+      "dependencies": {
+        "@tensorflow/tfjs-core": "1.7.0",
+        "tslib": "^1.11.1"
+      }
+    },
+    "node_modules/face-api.js/node_modules/@tensorflow/tfjs-core": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz",
+      "integrity": "sha512-uwQdiklNjqBnHPeseOdG0sGxrI3+d6lybaKu2+ou3ajVeKdPEwpWbgqA6iHjq1iylnOGkgkbbnQ6r2lwkiIIHw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/offscreencanvas": "~2019.3.0",
+        "@types/seedrandom": "2.4.27",
+        "@types/webgl-ext": "0.0.30",
+        "@types/webgl2": "0.0.4",
+        "node-fetch": "~2.1.2",
+        "seedrandom": "2.4.3"
+      },
+      "engines": {
+        "yarn": ">= 1.3.2"
+      }
+    },
+    "node_modules/face-api.js/node_modules/@types/offscreencanvas": {
+      "version": "2019.3.0",
+      "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz",
+      "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==",
+      "license": "MIT"
+    },
+    "node_modules/face-api.js/node_modules/@types/seedrandom": {
+      "version": "2.4.27",
+      "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz",
+      "integrity": "sha512-YvMLqFak/7rt//lPBtEHv3M4sRNA+HGxrhFZ+DQs9K2IkYJbNwVIb8avtJfhDiuaUBX/AW0jnjv48FV8h3u9bQ==",
+      "license": "MIT"
+    },
+    "node_modules/face-api.js/node_modules/node-fetch": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
+      "integrity": "sha512-IHLHYskTc2arMYsHZH82PVX8CSKT5lzb7AXeyO06QnjGDKtkv+pv3mEki6S7reB/x1QPo+YPxQRNEVgR5V/w3Q==",
+      "license": "MIT",
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      }
+    },
+    "node_modules/face-api.js/node_modules/seedrandom": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
+      "integrity": "sha512-2CkZ9Wn2dS4mMUWQaXLsOAfGD+irMlLEeSP3cMxpGbgyOOzJGFa+MWCOMTOCMyZinHRPxyOj/S/C57li/1to6Q==",
+      "license": "MIT"
+    },
+    "node_modules/face-api.js/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "license": "0BSD"
+    },
     "node_modules/fast-deep-equal": {
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -8605,31 +8802,6 @@
         "source-map-support": "^0.5.5"
         "source-map-support": "^0.5.5"
       }
       }
     },
     },
-    "node_modules/karma/node_modules/chokidar": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
     "node_modules/karma/node_modules/cliui": {
     "node_modules/karma/node_modules/cliui": {
       "version": "7.0.4",
       "version": "7.0.4",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -8649,19 +8821,6 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
-    "node_modules/karma/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/karma/node_modules/is-fullwidth-code-point": {
     "node_modules/karma/node_modules/is-fullwidth-code-point": {
       "version": "3.0.0",
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -8672,32 +8831,6 @@
         "node": ">=8"
         "node": ">=8"
       }
       }
     },
     },
-    "node_modules/karma/node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/karma/node_modules/readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "picomatch": "^2.2.1"
-      },
-      "engines": {
-        "node": ">=8.10.0"
-      }
-    },
     "node_modules/karma/node_modules/source-map": {
     "node_modules/karma/node_modules/source-map": {
       "version": "0.6.1",
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -9255,6 +9388,12 @@
         "node": ">=8.0"
         "node": ">=8.0"
       }
       }
     },
     },
+    "node_modules/long": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+      "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
+      "license": "Apache-2.0"
+    },
     "node_modules/lru-cache": {
     "node_modules/lru-cache": {
       "version": "5.1.1",
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -9879,6 +10018,26 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/node-fetch": {
+      "version": "2.6.13",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz",
+      "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/node-forge": {
     "node_modules/node-forge": {
       "version": "1.3.1",
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@@ -11070,17 +11229,29 @@
       }
       }
     },
     },
     "node_modules/readdirp": {
     "node_modules/readdirp": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
-      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
       "engines": {
       "engines": {
-        "node": ">= 14.16.0"
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
       },
       },
       "funding": {
       "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
+        "url": "https://github.com/sponsors/jonschlinkert"
       }
       }
     },
     },
     "node_modules/reflect-metadata": {
     "node_modules/reflect-metadata": {
@@ -11451,7 +11622,7 @@
       "version": "2.1.2",
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-      "dev": true,
+      "devOptional": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
     "node_modules/sass": {
     "node_modules/sass": {
@@ -11513,70 +11684,6 @@
         }
         }
       }
       }
     },
     },
-    "node_modules/sass/node_modules/chokidar": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/sass/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/sass/node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/sass/node_modules/readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "picomatch": "^2.2.1"
-      },
-      "engines": {
-        "node": ">=8.10.0"
-      }
-    },
     "node_modules/sax": {
     "node_modules/sax": {
       "version": "1.4.1",
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
@@ -11623,6 +11730,12 @@
         }
         }
       }
       }
     },
     },
+    "node_modules/seedrandom": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
+      "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==",
+      "license": "MIT"
+    },
     "node_modules/select-hose": {
     "node_modules/select-hose": {
       "version": "2.0.0",
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -12693,6 +12806,12 @@
         "node": ">=0.6"
         "node": ">=0.6"
       }
       }
     },
     },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
+    },
     "node_modules/tree-dump": {
     "node_modules/tree-dump": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz",
@@ -13605,6 +13724,12 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
     "node_modules/webpack": {
     "node_modules/webpack": {
       "version": "5.94.0",
       "version": "5.94.0",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
@@ -13752,31 +13877,6 @@
         "balanced-match": "^1.0.0"
         "balanced-match": "^1.0.0"
       }
       }
     },
     },
-    "node_modules/webpack-dev-server/node_modules/chokidar": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
     "node_modules/webpack-dev-server/node_modules/glob": {
     "node_modules/webpack-dev-server/node_modules/glob": {
       "version": "10.4.5",
       "version": "10.4.5",
       "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
       "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -13798,19 +13898,6 @@
         "url": "https://github.com/sponsors/isaacs"
         "url": "https://github.com/sponsors/isaacs"
       }
       }
     },
     },
-    "node_modules/webpack-dev-server/node_modules/glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "is-glob": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
     "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": {
       "version": "2.0.7",
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
       "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
@@ -13852,32 +13939,6 @@
         "url": "https://github.com/sponsors/isaacs"
         "url": "https://github.com/sponsors/isaacs"
       }
       }
     },
     },
-    "node_modules/webpack-dev-server/node_modules/picomatch": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-      "dev": true,
-      "license": "MIT",
-      "engines": {
-        "node": ">=8.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/jonschlinkert"
-      }
-    },
-    "node_modules/webpack-dev-server/node_modules/readdirp": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "picomatch": "^2.2.1"
-      },
-      "engines": {
-        "node": ">=8.10.0"
-      }
-    },
     "node_modules/webpack-dev-server/node_modules/rimraf": {
     "node_modules/webpack-dev-server/node_modules/rimraf": {
       "version": "5.0.10",
       "version": "5.0.10",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
@@ -14026,6 +14087,16 @@
         "node": ">=0.8.0"
         "node": ">=0.8.0"
       }
       }
     },
     },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "node_modules/which": {
     "node_modules/which": {
       "version": "1.3.1",
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",

+ 3 - 0
package.json

@@ -18,6 +18,9 @@
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/router": "^18.0.0",
     "@angular/router": "^18.0.0",
+    "@tensorflow/tfjs-core": "^4.22.0",
+    "bootstrap": "^5.3.3",
+    "face-api.js": "^0.22.2",
     "rxjs": "~7.8.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.14.3"
     "zone.js": "~0.14.3"

BIN
public/assets/models/age_gender_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/age_gender_model-weights_manifest.json


BIN
public/assets/models/face_expression_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/face_expression_model-weights_manifest.json


BIN
public/assets/models/face_landmark_68_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/face_landmark_68_model-weights_manifest.json


BIN
public/assets/models/face_landmark_68_tiny_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/face_landmark_68_tiny_model-weights_manifest.json


BIN
public/assets/models/face_recognition_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/face_recognition_model-shard2


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/face_recognition_model-weights_manifest.json


BIN
public/assets/models/mtcnn_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/mtcnn_model-weights_manifest.json


BIN
public/assets/models/ssd_mobilenetv1_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/ssd_mobilenetv1_model-shard2


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/ssd_mobilenetv1_model-weights_manifest.json


BIN
public/assets/models/tiny_face_detector_model-shard1


File diff suppressed because it is too large
+ 0 - 0
public/assets/models/tiny_face_detector_model-weights_manifest.json


File diff suppressed because it is too large
+ 0 - 191
src/app/app.component.html


+ 7 - 3
src/app/app.component.ts

@@ -1,13 +1,17 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
 import { RouterOutlet } from '@angular/router';
 import { RouterOutlet } from '@angular/router';
-
+import { AuthService } from './auth/auth.service';
+import { inject } from '@angular/core';
+import { CommonModule } from '@angular/common';
 @Component({
 @Component({
   selector: 'app-root',
   selector: 'app-root',
   standalone: true,
   standalone: true,
-  imports: [RouterOutlet],
+  imports: [RouterOutlet,CommonModule],
   templateUrl: './app.component.html',
   templateUrl: './app.component.html',
   styleUrl: './app.component.css'
   styleUrl: './app.component.css'
 })
 })
 export class AppComponent {
 export class AppComponent {
-  title = 'rvc';
+
+  title = 'Reverify';
+
 }
 }

+ 6 - 1
src/app/app.config.ts

@@ -2,7 +2,12 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
 import { provideRouter } from '@angular/router';
 import { provideRouter } from '@angular/router';
 
 
 import { routes } from './app.routes';
 import { routes } from './app.routes';
+import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
+import { provideClientHydration } from '@angular/platform-browser';
+
+import { ErrorInterceptor } from './interceptors/error.interceptor';
 
 
 export const appConfig: ApplicationConfig = {
 export const appConfig: ApplicationConfig = {
-  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
+  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(),provideHttpClient(withInterceptorsFromDi()),
+    { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }]
 };
 };

+ 23 - 1
src/app/app.routes.ts

@@ -1,3 +1,25 @@
 import { Routes } from '@angular/router';
 import { Routes } from '@angular/router';
+import { LoginComponent } from './pages/login/login.component';
+import { RegisterComponent } from './pages/register/register.component';
+import { DashboardComponent } from './pages/dashboard/dashboard.component';
+import { authGuard } from './auth/auth.guard';
+import { FaceComponent } from './pages/face/face.component';
+export const routes: Routes = [
+    {
+        path: '', redirectTo: '/login', pathMatch: 'full'
+    },
+    {
+        path: 'login', component: LoginComponent
+    },
+    {
+        path: 'register', component: RegisterComponent
+    },
 
 
-export const routes: Routes = [];
+    {
+        path: 'dashboard', component: DashboardComponent, canActivate: [authGuard]
+    },
+
+    {
+        path: 'face', component: FaceComponent, canActivate: [authGuard]
+    }
+];

+ 17 - 0
src/app/auth/auth.guard.spec.ts

@@ -0,0 +1,17 @@
+import { TestBed } from '@angular/core/testing';
+import { CanActivateFn } from '@angular/router';
+
+import { authGuard } from './auth.guard';
+
+describe('authGuard', () => {
+  const executeGuard: CanActivateFn = (...guardParameters) => 
+      TestBed.runInInjectionContext(() => authGuard(...guardParameters));
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+  });
+
+  it('should be created', () => {
+    expect(executeGuard).toBeTruthy();
+  });
+});

+ 13 - 0
src/app/auth/auth.guard.ts

@@ -0,0 +1,13 @@
+import { CanActivateFn } from '@angular/router';
+import { inject } from '@angular/core';
+import { Router } from '@angular/router';
+import { AuthService } from './auth.service';
+export const authGuard: CanActivateFn = (route, state) => {
+  const  authService  =  inject(AuthService);
+  const  router  =  inject(Router);
+  if (authService.isLoggedIn()) {
+    return true;
+  }
+  router.navigate(['/login']);
+  return false;
+};

+ 16 - 0
src/app/auth/auth.service.spec.ts

@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthService } from './auth.service';
+
+describe('AuthService', () => {
+  let service: AuthService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(AuthService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});

+ 29 - 0
src/app/auth/auth.service.ts

@@ -0,0 +1,29 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { inject } from '@angular/core';
+import { tap } from 'rxjs/operators';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class AuthService {
+
+  httpClient = inject(HttpClient);
+  baseUrl = 'https://api.reverify.org/v1';
+  constructor() { }
+  signup(data: any) {
+    return this.httpClient.post(`${this.baseUrl}/register.php`, data);
+  }
+  login(data: any) {
+    return this.httpClient.post(`${this.baseUrl}/login.php`, data)
+      .pipe(tap((result) => {
+        localStorage.setItem('authUser', JSON.stringify(result));
+      }));
+  }
+  logout() {
+    localStorage.removeItem('authUser');
+  }
+  isLoggedIn() {
+    return localStorage.getItem('authUser') !== null;
+  }
+}

+ 17 - 0
src/app/interceptors/error.interceptor.spec.ts

@@ -0,0 +1,17 @@
+import { TestBed } from '@angular/core/testing';
+import { HttpInterceptorFn } from '@angular/common/http';
+
+import { errorInterceptor } from './error.interceptor';
+
+describe('errorInterceptor', () => {
+  const interceptor: HttpInterceptorFn = (req, next) => 
+    TestBed.runInInjectionContext(() => errorInterceptor(req, next));
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+  });
+
+  it('should be created', () => {
+    expect(interceptor).toBeTruthy();
+  });
+});

+ 25 - 0
src/app/interceptors/error.interceptor.ts

@@ -0,0 +1,25 @@
+import { Injectable } from '@angular/core';
+import {
+  HttpInterceptor,
+  HttpRequest,
+  HttpHandler,
+  HttpErrorResponse
+} from '@angular/common/http';
+import { catchError } from 'rxjs/operators';
+import { throwError } from 'rxjs';
+import { ErrorHandlerService } from '../services/error-handler.service';
+
+@Injectable()
+export class ErrorInterceptor implements HttpInterceptor {
+
+  constructor(private errorHandlerService: ErrorHandlerService) {}
+
+  intercept(request: HttpRequest<any>, next: HttpHandler) {
+    return next.handle(request).pipe(
+      catchError((error: HttpErrorResponse) => {
+        this.errorHandlerService.handleError(error);
+        return throwError(error);
+      })
+    );
+  }
+}

+ 2 - 0
src/app/interceptors/error.ts

@@ -0,0 +1,2 @@
+export interface Error {
+}

+ 3 - 0
src/app/pages/dashboard/dashboard.component.css

@@ -0,0 +1,3 @@
+main > .container {
+    padding: 60px 15px 0;
+  }

+ 203 - 0
src/app/pages/dashboard/dashboard.component.html

@@ -0,0 +1,203 @@
+<header>
+  <!-- Fixed navbar -->
+  <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+    <div class="container">
+      <a class="navbar-brand" href="#">Container</a>
+      <button
+        class="navbar-toggler"
+        type="button"
+        data-bs-toggle="collapse"
+        data-bs-target="#navbarsExample07"
+        aria-controls="navbarsExample07"
+        aria-expanded="false"
+        aria-label="Toggle navigation"
+      >
+        <span class="navbar-toggler-icon"></span>
+      </button>
+
+      <div class="collapse navbar-collapse" id="navbarsExample07">
+        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+          <li class="nav-item">
+            <a class="nav-link active" aria-current="page" href="/dashboard"
+              >Home</a
+            >
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">Link</a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" aria-disabled="false" href="/face"
+              >Face Recognition</a
+            >
+          </li>
+          <li class="nav-item dropdown">
+            <a
+              class="nav-link dropdown-toggle"
+              href="#"
+              data-bs-toggle="dropdown"
+              aria-expanded="false"
+              >How To ?</a
+            >
+            <ul class="dropdown-menu">
+              <li><a class="dropdown-item" href="#">Action</a></li>
+              <li><a class="dropdown-item" href="#">Another action</a></li>
+              <li><a class="dropdown-item" href="#">Something else here</a></li>
+            </ul>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" aria-disabled="false" (click)="logout()"
+              >Log Out</a
+            >
+          </li>
+        </ul>
+      </div>
+    </div>
+  </nav>
+</header>
+
+<!-- Begin page content -->
+<main class="flex-shrink-0">
+  <div class="container">
+    <h1 class="mt-5">Sticky footer with fixed navbar</h1>
+    <p class="lead">
+      Pin a footer to the bottom of the viewport in desktop browsers with this
+      custom HTML and CSS. A fixed navbar has been added with
+      <code class="small">padding-top: 60px;</code> on the
+      <code class="small">main &gt; .container</code>.
+    </p>
+    <p>
+      he standard Lorem Ipsum passage, used since the 1500s "Lorem ipsum dolor
+      sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
+      labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+      exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+      aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+      fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
+      sunt in culpa qui officia deserunt mollit anim id est laborum." Section
+      1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
+      "Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+      accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab
+      illo inventore veritatis et quasi architecto beatae vitae dicta sunt
+      explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut
+      odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
+      voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum
+      quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam
+      eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat
+      voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam
+      corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
+      Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
+      nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas
+      nulla pariatur?" 1914 translation by H. Rackham "But I must explain to you
+      how all this mistaken idea of denouncing pleasure and praising pain was
+      born and I will give you a complete account of the system, and expound the
+      actual teachings of the great explorer of the truth, the master-builder of
+      human happiness. No one rejects, dislikes, or avoids pleasure itself,
+      because it is pleasure, but because those who do not know how to pursue
+      pleasure rationally encounter consequences that are extremely painful. Nor
+      again is there anyone who loves or pursues or desires to obtain pain of
+      itself, because it is pain, but because occasionally circumstances occur
+      in which toil and pain can procure him some great pleasure. To take a
+      trivial example, which of us ever undertakes laborious physical exercise,
+      except to obtain some advantage from it? But who has any right to find
+      fault with a man who chooses to enjoy a pleasure that has no annoying
+      consequences, or one who avoids a pain that produces no resultant
+      pleasure?" Section 1.10.33 of "de Finibus Bonorum et Malorum", written by
+      Cicero in 45 BC "At vero eos et accusamus et iusto odio dignissimos
+      ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos
+      dolores et quas molestias excepturi sint occaecati cupiditate non
+      provident, similique sunt in culpa qui officia deserunt mollitia animi, id
+      est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita
+      distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque
+      nihil impedit quo minus id quod maxime placeat facere possimus, omnis
+      voluptas assumenda est, omnis dolor repellendus. Temporibus autem
+      quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet
+      ut et voluptates repudiandae sint et molestiae non recusandae. Itaque
+      earum rerum hic tenetur a sapiente delectus, ut aut reiciendis
+      voluptatibus maiores alias consequatur aut perferendis doloribus
+      asperiores repellat." 1914 translation by H. Rackham "On the other hand,
+      we denounce with righteous indignation and dislike men who are so beguiled
+      and demoralized by the charms of pleasure of the moment, so blinded by
+      desire, that they cannot foresee the pain and trouble that are bound to
+      ensue; and equal blame belongs to those who fail in their duty through
+      weakness of will, which is the same as saying through shrinking from toil
+      and pain. These cases are perfectly simple and easy to distinguish. In a
+      free hour, when our power of choice is untrammelled and when nothing
+      prevents our being able to do what we like best, every pleasure is to be
+      welcomed and every pain avoided. But in certain circumstances and owing to
+      the claims of duty or the obligations of business it will frequently occur
+      that pleasures have to be repudiated and annoyances accepted. The wise man
+      therefore always holds in these matters to this principle of selection: he
+      rejects pleasures to secure other greater pleasures, or else he endures
+      pains to avoid worse pains."
+    </p>
+    <p>
+      he standard Lorem Ipsum passage, used since the 1500s "Lorem ipsum dolor
+      sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
+      labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
+      exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+      aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+      fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,
+      sunt in culpa qui officia deserunt mollit anim id est laborum." Section
+      1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
+      "Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+      accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab
+      illo inventore veritatis et quasi architecto beatae vitae dicta sunt
+      explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut
+      odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
+      voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum
+      quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam
+      eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat
+      voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam
+      corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
+      Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
+      nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas
+      nulla pariatur?" 1914 translation by H. Rackham "But I must explain to you
+      how all this mistaken idea of denouncing pleasure and praising pain was
+      born and I will give you a complete account of the system, and expound the
+      actual teachings of the great explorer of the truth, the master-builder of
+      human happiness. No one rejects, dislikes, or avoids pleasure itself,
+      because it is pleasure, but because those who do not know how to pursue
+      pleasure rationally encounter consequences that are extremely painful. Nor
+      again is there anyone who loves or pursues or desires to obtain pain of
+      itself, because it is pain, but because occasionally circumstances occur
+      in which toil and pain can procure him some great pleasure. To take a
+      trivial example, which of us ever undertakes laborious physical exercise,
+      except to obtain some advantage from it? But who has any right to find
+      fault with a man who chooses to enjoy a pleasure that has no annoying
+      consequences, or one who avoids a pain that produces no resultant
+      pleasure?" Section 1.10.33 of "de Finibus Bonorum et Malorum", written by
+      Cicero in 45 BC "At vero eos et accusamus et iusto odio dignissimos
+      ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos
+      dolores et quas molestias excepturi sint occaecati cupiditate non
+      provident, similique sunt in culpa qui officia deserunt mollitia animi, id
+      est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita
+      distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque
+      nihil impedit quo minus id quod maxime placeat facere possimus, omnis
+      voluptas assumenda est, omnis dolor repellendus. Temporibus autem
+      quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet
+      ut et voluptates repudiandae sint et molestiae non recusandae. Itaque
+      earum rerum hic tenetur a sapiente delectus, ut aut reiciendis
+      voluptatibus maiores alias consequatur aut perferendis doloribus
+      asperiores repellat." 1914 translation by H. Rackham "On the other hand,
+      we denounce with righteous indignation and dislike men who are so beguiled
+      and demoralized by the charms of pleasure of the moment, so blinded by
+      desire, that they cannot foresee the pain and trouble that are bound to
+      ensue; and equal blame belongs to those who fail in their duty through
+      weakness of will, which is the same as saying through shrinking from toil
+      and pain. These cases are perfectly simple and easy to distinguish. In a
+      free hour, when our power of choice is untrammelled and when nothing
+      prevents our being able to do what we like best, every pleasure is to be
+      welcomed and every pain avoided. But in certain circumstances and owing to
+      the claims of duty or the obligations of business it will frequently occur
+      that pleasures have to be repudiated and annoyances accepted. The wise man
+      therefore always holds in these matters to this principle of selection: he
+      rejects pleasures to secure other greater pleasures, or else he endures
+      pains to avoid worse pains."
+    </p>
+  </div>
+</main>
+
+<footer class="footer mt-auto py-3 bg-body-tertiary fixed-bottom">
+  <div class="container">
+    <span class="text-body-secondary">Place sticky footer content here.</span>
+  </div>
+</footer>

+ 23 - 0
src/app/pages/dashboard/dashboard.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DashboardComponent } from './dashboard.component';
+
+describe('DashboardComponent', () => {
+  let component: DashboardComponent;
+  let fixture: ComponentFixture<DashboardComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [DashboardComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(DashboardComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 18 - 0
src/app/pages/dashboard/dashboard.component.ts

@@ -0,0 +1,18 @@
+import { Component, inject } from '@angular/core';
+import { Router } from '@angular/router';
+import { AuthService } from '../../auth/auth.service';
+@Component({
+  selector: 'app-dashboard',
+  standalone: true,
+  imports: [],
+  templateUrl: './dashboard.component.html',
+  styleUrl: './dashboard.component.css'
+})
+export class DashboardComponent {
+  authService = inject(AuthService);
+  router = inject(Router);
+  public logout(){
+    this.authService.logout();
+    this.router.navigate(['/login']);
+  }
+}

+ 8 - 0
src/app/pages/face/face.component.css

@@ -0,0 +1,8 @@
+.video-container {
+    position: absolute;
+    top:100px;
+    left: auto;
+    right: auto;
+    
+    margin: auto;
+}

+ 87 - 0
src/app/pages/face/face.component.html

@@ -0,0 +1,87 @@
+<header>
+  <!-- Fixed navbar -->
+  <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+    <div class="container">
+      <a class="navbar-brand" href="#">Container</a>
+      <button
+        class="navbar-toggler"
+        type="button"
+        data-bs-toggle="collapse"
+        data-bs-target="#navbarsExample07"
+        aria-controls="navbarsExample07"
+        aria-expanded="false"
+        aria-label="Toggle navigation"
+      >
+        <span class="navbar-toggler-icon"></span>
+      </button>
+
+      <div class="collapse navbar-collapse" id="navbarsExample07">
+        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+          <li class="nav-item">
+            <a class="nav-link" aria-current="page" href="/dashboard">Home</a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">Link</a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link active" aria-disabled="false" href="/face"
+              >Face Recognition</a
+            >
+          </li>
+          <li class="nav-item dropdown">
+            <a
+              class="nav-link dropdown-toggle"
+              href="#"
+              data-bs-toggle="dropdown"
+              aria-expanded="false"
+              >How To ?</a
+            >
+            <ul class="dropdown-menu">
+              <li><a class="dropdown-item" href="#">Action</a></li>
+              <li><a class="dropdown-item" href="#">Another action</a></li>
+              <li><a class="dropdown-item" href="#">Something else here</a></li>
+            </ul>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" aria-disabled="false" (click)="logout()"
+              >Log Out</a
+            >
+          </li>
+        </ul>
+      </div>
+    </div>
+  </nav>
+</header>
+
+<!-- Begin page content -->
+<main class="flex-shrink-0">
+  <div class="container">
+    <div class="row">
+      <div class="col">
+        <div class="d-flex justify-content-center">
+          <div class="video-container">
+            <video
+              #video
+              [width]="WIDTH"
+              [height]="HEIGHT"
+              autoplay
+              muted
+            ></video>
+            <div #canvas></div>
+          </div>
+        </div>
+      </div>
+      <div class="col">
+        <div class="d-flex justify-content-center">
+          <div id="screenshot">123</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</main>
+
+<footer class="footer mt-auto py-3 bg-body-tertiary fixed-bottom">
+  <div class="container">
+    <span class="text-body-secondary">Place sticky footer content here.</span>
+  </div>
+</footer>

+ 23 - 0
src/app/pages/face/face.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FaceComponent } from './face.component';
+
+describe('FaceComponent', () => {
+  let component: FaceComponent;
+  let fixture: ComponentFixture<FaceComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [FaceComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(FaceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 112 - 0
src/app/pages/face/face.component.ts

@@ -0,0 +1,112 @@
+import {
+  Component,
+  ElementRef,
+  inject,
+  OnInit,
+  ViewChild,
+} from '@angular/core';
+import { Router } from '@angular/router';
+import { AuthService } from '../../auth/auth.service';
+import * as faceapi from 'face-api.js';
+@Component({
+  selector: 'app-face',
+  standalone: true,
+  imports: [],
+  templateUrl: './face.component.html',
+  styleUrl: './face.component.css',
+})
+export class FaceComponent implements OnInit {
+  authService = inject(AuthService);
+  router = inject(Router);
+  public logout() {
+    this.authService.logout();
+    this.router.navigate(['/login']);
+  }
+
+  WIDTH = 440;
+  HEIGHT = 280;
+  @ViewChild('video', { static: true })
+  public video!: ElementRef;
+  @ViewChild('canvas', { static: true })
+  public canvasRef!: ElementRef;
+  constructor(private elRef: ElementRef) {}
+  stream: any;
+  detection: any;
+  resizedDetections: any;
+  canvas: any;
+  canvasEl: any;
+  displaySize: any;
+  videoInput: any;
+  canvasCapture: any;
+  async ngOnInit() {
+    await Promise.all([
+      faceapi.nets.tinyFaceDetector.loadFromUri('assets/models'),
+      await faceapi.nets.faceLandmark68Net.loadFromUri('assets/models'),
+      await faceapi.nets.faceRecognitionNet.loadFromUri('assets/models'),
+      await faceapi.nets.faceExpressionNet.loadFromUri('assets/models'),
+    ]).then(() => this.startVideo());
+  }
+
+  startVideo() {
+    this.videoInput = this.video.nativeElement;
+    navigator.mediaDevices.getUserMedia({ video: {}, audio: false }).then(
+      (stream) => (this.videoInput.srcObject = stream),
+      (err) => console.log(err)
+    );
+    this.detect_Faces();
+  }
+
+  async detect_Faces() {
+    this.elRef.nativeElement
+      .querySelector('video')
+      .addEventListener('play', async () => {
+        this.canvas = await faceapi.createCanvasFromMedia(this.videoInput);
+        this.canvasEl = this.canvasRef.nativeElement;
+        this.canvasEl.appendChild(this.canvas);
+        this.canvas.setAttribute('id', 'canvass');
+        this.canvas.setAttribute(
+          'style',
+          `position: fixed;
+          top: 100px;
+          left: auto;
+          right: auto;
+          `
+        );
+        this.displaySize = {
+          width: this.videoInput.width,
+          height: this.videoInput.height,
+        };
+        faceapi.matchDimensions(this.canvas, this.displaySize);
+        setInterval(async () => {
+          this.detection = await faceapi
+            .detectAllFaces(
+              this.videoInput,
+              new faceapi.TinyFaceDetectorOptions()
+            )
+            .withFaceLandmarks()
+            .withFaceExpressions();
+          this.resizedDetections = faceapi.resizeResults(
+            this.detection,
+            this.displaySize
+          );
+          //console.log(this.resizedDetections[0]['expressions']['happy']);
+          if (this.resizedDetections[0]['expressions']['happy']! > 0.8) {
+            //alert("Happy");
+            const canvasCapture = document.createElement('canvas');
+            canvasCapture.width = 500;
+            canvasCapture.height = 500;
+            canvasCapture.getContext('2d')!.drawImage(this.videoInput, 0, 0);
+            const img = document.createElement('img');
+            img.src = canvasCapture.toDataURL('image/webp');
+            document.getElementById('screenshot')!.replaceChildren(img);
+          }
+          this.canvas
+            .getContext('2d')
+            .clearRect(0, 0, this.canvas.width, this.canvas.height);
+          faceapi.draw.drawDetections(this.canvas, this.resizedDetections);
+          faceapi.draw.drawFaceLandmarks(this.canvas, this.resizedDetections);
+          faceapi.draw.drawFaceExpressions(this.canvas, this.resizedDetections);
+        }, 100);
+      });
+  }
+}

+ 0 - 0
src/app/pages/header/header.component.css


+ 38 - 0
src/app/pages/header/header.component.html

@@ -0,0 +1,38 @@
+ 
+<header>
+    <!-- Fixed navbar -->
+     <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+        <div class="container ">
+            <a class="navbar-brand" href="#">Container</a>
+            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarsExample07" aria-controls="navbarsExample07" aria-expanded="false" aria-label="Toggle navigation">
+              <span class="navbar-toggler-icon"></span>
+            </button>
+      
+            <div class="collapse navbar-collapse" id="navbarsExample07">
+              <ul class="navbar-nav me-auto mb-2 mb-lg-0">
+                <li class="nav-item">
+                  <a class="nav-link active" aria-current="page" href="#">Home</a>
+                </li>
+                <li class="nav-item">
+                  <a class="nav-link" href="#">Link</a>
+                </li>
+                <li class="nav-item">
+                  <a class="nav-link disabled" aria-disabled="true">Disabled</a>
+                </li>
+                <li class="nav-item dropdown">
+                  <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
+                  <ul class="dropdown-menu">
+                    <li><a class="dropdown-item" href="#">Action</a></li>
+                    <li><a class="dropdown-item" href="#">Another action</a></li>
+                    <li><a class="dropdown-item" href="#">Something else here</a></li>
+                  </ul>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" aria-disabled="false">Log Out</a>
+                  </li>
+              </ul>
+            </div>
+          </div>
+    </nav>
+    </header>
+    

+ 23 - 0
src/app/pages/header/header.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HeaderComponent } from './header.component';
+
+describe('HeaderComponent', () => {
+  let component: HeaderComponent;
+  let fixture: ComponentFixture<HeaderComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [HeaderComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(HeaderComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 19 - 0
src/app/pages/header/header.component.ts

@@ -0,0 +1,19 @@
+import { Component, inject } from '@angular/core';
+import { Router } from 'express';
+import { AuthService } from '../../auth/auth.service';
+
+@Component({
+  selector: 'app-header',
+  standalone: true,
+  imports: [],
+  templateUrl: './header.component.html',
+  styleUrl: './header.component.css'
+})
+export class HeaderComponent {
+  authService = inject(AuthService);
+  router = inject(Router);
+  public logout(){
+    this.authService.logout();
+    this.router.navigate(['/login']);
+  }
+}

+ 0 - 0
src/app/pages/login/login.component.css


+ 29 - 0
src/app/pages/login/login.component.html

@@ -0,0 +1,29 @@
+<div id="login">
+    <h3 class="text-center text-white pt-5">Login form</h3>
+    <div class="container">
+        <div id="login-row" class="row justify-content-center align-items-center">
+            <div id="login-column" class="col-md-6">
+                <div id="login-box" class="col-md-12">
+                    <form id="loginForm" class="form" [formGroup]="loginForm" (ngSubmit)="onSubmit()">
+                        <h3 class="text-center text-info">Login</h3>
+                        <div class="form-group">
+                            <label for="username" class="text-info">Username:</label><br>
+                            <input type="text" name="username" id="username" formControlName="username" class="form-control">
+                        </div>
+                        <div class="form-group">
+                            <label for="password" class="text-info">Password:</label><br>
+                            <input type="password" name="password" id="password" formControlName="password" class="form-control">
+                        </div>
+                        <div class="form-group">
+                            <label for="remember-me" class="text-info"><span>Remember me</span> <span><input id="remember-me" name="remember-me" type="checkbox"></span></label><br>
+                            <input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
+                        </div>
+                        <div id="register-link" class="text-right">
+                            <a href="/register" class="text-info">Register here</a>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 23 - 0
src/app/pages/login/login.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LoginComponent } from './login.component';
+
+describe('LoginComponent', () => {
+  let component: LoginComponent;
+  let fixture: ComponentFixture<LoginComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [LoginComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(LoginComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 33 - 0
src/app/pages/login/login.component.ts

@@ -0,0 +1,33 @@
+import { Component } from '@angular/core';
+import { inject } from '@angular/core';
+import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
+import { Router, RouterModule } from '@angular/router';
+import { AuthService } from '../../auth/auth.service';
+
+@Component({
+  selector: 'app-login',
+  standalone: true,
+  imports: [ ReactiveFormsModule, RouterModule],
+  templateUrl: './login.component.html',
+  styleUrl: './login.component.css'
+})
+export class LoginComponent {
+  authService = inject(AuthService);
+  router = inject(Router);
+  protected loginForm = new FormGroup({
+    username: new FormControl('', [Validators.required, Validators.email]),
+    password: new FormControl('', [Validators.required])
+  })
+  onSubmit(){
+    if(this.loginForm.valid){
+      //console.log(this.loginForm.value);
+      this.authService.login(this.loginForm.value)
+      .subscribe((data: any) => {
+        if(this.authService.isLoggedIn()){
+          this.router.navigate(['/dashboard']);
+        }
+        //console.log(data);
+      });
+    }
+  }
+}

+ 0 - 0
src/app/pages/register/register.component.css


+ 1 - 0
src/app/pages/register/register.component.html

@@ -0,0 +1 @@
+<p>register works!</p>

+ 23 - 0
src/app/pages/register/register.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RegisterComponent } from './register.component';
+
+describe('RegisterComponent', () => {
+  let component: RegisterComponent;
+  let fixture: ComponentFixture<RegisterComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [RegisterComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(RegisterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 12 - 0
src/app/pages/register/register.component.ts

@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-register',
+  standalone: true,
+  imports: [],
+  templateUrl: './register.component.html',
+  styleUrl: './register.component.css'
+})
+export class RegisterComponent {
+
+}

+ 16 - 0
src/app/services/error-handler.service.spec.ts

@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { ErrorHandlerService } from './error-handler.service';
+
+describe('ErrorHandlerService', () => {
+  let service: ErrorHandlerService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(ErrorHandlerService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});

+ 40 - 0
src/app/services/error-handler.service.ts

@@ -0,0 +1,40 @@
+import { Injectable } from '@angular/core';
+import { HttpErrorResponse } from '@angular/common/http';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ErrorHandlerService {
+
+  public handleError(error: HttpErrorResponse): void {
+    if (error.error instanceof ErrorEvent) {
+      // Client-side or network error
+      //console.error('An error occurred:', error.error.message);
+    } else {
+      // Backend returned an unsuccessful response code
+      //console.error(`Backend returned code ${error.status}, body was: `, error.error);
+      this.handleServerError(error);
+    }
+  }
+
+  private handleServerError(error: HttpErrorResponse): void {
+    switch (error.status) {
+      case 401:
+        alert(error.message);
+        break;
+      case 403:
+        alert(error.error.message);
+        break;
+      case 404:
+        alert(error.message);
+        break;
+      case 500:
+        alert(error.message);
+        break;
+      // Add more cases as needed
+      default:
+        alert(error.message);
+        break;
+    }
+  }
+}

+ 4 - 2
src/index.html

@@ -2,12 +2,14 @@
 <html lang="en">
 <html lang="en">
 <head>
 <head>
   <meta charset="utf-8">
   <meta charset="utf-8">
-  <title>Rvc</title>
+  <title>Reverify</title>
   <base href="/">
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
 </head>
 </head>
-<body>
+<body class="d-flex flex-column h-100">
   <app-root></app-root>
   <app-root></app-root>
+  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
 </body>
 </body>
 </html>
 </html>

+ 3 - 0
src/styles.css

@@ -1 +1,4 @@
 /* You can add global styles to this file, and also import other style files */
 /* You can add global styles to this file, and also import other style files */
+html {
+    padding-bottom: 60px;
+}

Some files were not shown because too many files changed in this diff