@utamuratov/ngx-face-id 0.3.1 → 0.3.2
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { signal, computed, Injectable, inject, PLATFORM_ID, output, ViewChild, Component } from '@angular/core';
|
|
3
|
-
import { isPlatformBrowser
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
4
|
import * as faceapi from 'face-api.js';
|
|
5
5
|
|
|
6
6
|
class LivenessService {
|
|
@@ -152,6 +152,7 @@ class NgxFaceLiveness {
|
|
|
152
152
|
videoRef;
|
|
153
153
|
intervalId;
|
|
154
154
|
capturedImage = output();
|
|
155
|
+
capturesImageSrc = signal(null, ...(ngDevMode ? [{ debugName: "capturesImageSrc" }] : []));
|
|
155
156
|
constructor(liveness) {
|
|
156
157
|
this.liveness = liveness;
|
|
157
158
|
}
|
|
@@ -220,6 +221,7 @@ class NgxFaceLiveness {
|
|
|
220
221
|
}
|
|
221
222
|
sendToBackend(blob) {
|
|
222
223
|
this.capturedImage.emit(blob);
|
|
224
|
+
this.capturesImageSrc.set(URL.createObjectURL(blob));
|
|
223
225
|
console.log(blob);
|
|
224
226
|
// const fd = new FormData();
|
|
225
227
|
// fd.append('file', blob, 'face.jpg');
|
|
@@ -250,31 +252,37 @@ class NgxFaceLiveness {
|
|
|
250
252
|
this.liveness.reset();
|
|
251
253
|
}
|
|
252
254
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NgxFaceLiveness, deps: [{ token: LivenessService }], target: i0.ɵɵFactoryTarget.Component });
|
|
253
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
255
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: NgxFaceLiveness, isStandalone: true, selector: "ngx-face-liveness", outputs: { capturedImage: "capturedImage" }, viewQueries: [{ propertyName: "videoRef", first: true, predicate: ["video"], descendants: true }], ngImport: i0, template: `
|
|
254
256
|
<div class="camera-wrapper">
|
|
257
|
+
@if (capturesImageSrc()) {
|
|
258
|
+
<img [src]="capturesImageSrc()" alt="Captured Image" class="captured-image" />
|
|
259
|
+
}
|
|
255
260
|
<video #video autoplay muted playsinline class="camera-video"></video>
|
|
256
261
|
|
|
257
262
|
<!-- Overlay -->
|
|
258
263
|
<div class="overlay">
|
|
259
|
-
<div class="oval-mask" [
|
|
264
|
+
<div class="oval-mask" [style.borderColor]="isNotValidOval() ? '#fb2c36' : '#65a0f8'"></div>
|
|
260
265
|
<p class="hint">{{ stepText() }}</p>
|
|
261
266
|
</div>
|
|
262
267
|
</div>
|
|
263
|
-
`, isInline: true, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:640px;aspect-ratio:4/3;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:50%;aspect-ratio:5/6;border-radius:50%;border:
|
|
268
|
+
`, isInline: true, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:640px;aspect-ratio:4/3;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:50%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{margin-top:12px;color:#fff;font-size:14px;text-align:center;position:absolute;top:5px;background-color:#0000007a;padding:2px 4px;border-radius:5px}.captured-image{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;border-radius:12px}\n"] });
|
|
264
269
|
}
|
|
265
270
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NgxFaceLiveness, decorators: [{
|
|
266
271
|
type: Component,
|
|
267
|
-
args: [{ selector: 'ngx-face-liveness',
|
|
272
|
+
args: [{ selector: 'ngx-face-liveness', template: `
|
|
268
273
|
<div class="camera-wrapper">
|
|
274
|
+
@if (capturesImageSrc()) {
|
|
275
|
+
<img [src]="capturesImageSrc()" alt="Captured Image" class="captured-image" />
|
|
276
|
+
}
|
|
269
277
|
<video #video autoplay muted playsinline class="camera-video"></video>
|
|
270
278
|
|
|
271
279
|
<!-- Overlay -->
|
|
272
280
|
<div class="overlay">
|
|
273
|
-
<div class="oval-mask" [
|
|
281
|
+
<div class="oval-mask" [style.borderColor]="isNotValidOval() ? '#fb2c36' : '#65a0f8'"></div>
|
|
274
282
|
<p class="hint">{{ stepText() }}</p>
|
|
275
283
|
</div>
|
|
276
284
|
</div>
|
|
277
|
-
`, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:640px;aspect-ratio:4/3;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:50%;aspect-ratio:5/6;border-radius:50%;border:
|
|
285
|
+
`, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:640px;aspect-ratio:4/3;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:50%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{margin-top:12px;color:#fff;font-size:14px;text-align:center;position:absolute;top:5px;background-color:#0000007a;padding:2px 4px;border-radius:5px}.captured-image{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;border-radius:12px}\n"] }]
|
|
278
286
|
}], ctorParameters: () => [{ type: LivenessService }], propDecorators: { videoRef: [{
|
|
279
287
|
type: ViewChild,
|
|
280
288
|
args: ['video']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utamuratov-ngx-face-id.mjs","sources":["../../../projects/ngx-face-id/src/lib/face-liveness/liveness.service.ts","../../../projects/ngx-face-id/src/lib/face-liveness/face-liveness.ts","../../../projects/ngx-face-id/src/public-api.ts","../../../projects/ngx-face-id/src/utamuratov-ngx-face-id.ts"],"sourcesContent":["import { computed, Injectable, signal } from '@angular/core';\nimport * as faceapi from 'face-api.js';\n\ntype Step =\n // | 'NO_FACE'\n // | 'OUTSIDE_OVAL'\n // | 'COME_CLOSE'\n // | 'VERY_CLOSE'\n 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';\n\ntype FaceInside = 'NO_FACE' | 'OUTSIDE_OVAL' | 'COME_CLOSE' | 'VERY_CLOSE' | 'VALID';\n\n@Injectable({ providedIn: 'root' })\nexport class LivenessService {\n private step = signal<Step>('BLINK');\n private faceInsideStatus = signal<FaceInside>('OUTSIDE_OVAL');\n currentStep = computed(() => this.step());\n currentFaceInsideStatus = computed(() => this.faceInsideStatus());\n\n private prevBlinkAvg = 0;\n private blinkCount = 0;\n private prevNoseX?: number;\n private holdStart?: number;\n\n async loadModels() {\n const MODEL_URL = '/models';\n await Promise.all([\n faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),\n faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),\n faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),\n ]);\n }\n\n reset() {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n this.step.set('BLINK');\n this.blinkCount = 0;\n this.prevBlinkAvg = 0;\n this.prevNoseX = undefined;\n this.holdStart = undefined;\n }\n\n // ---------- HELPERS ----------\n\n private isFaceInsideOval(box: faceapi.Box, video: HTMLVideoElement): boolean {\n const cx = video.videoWidth / 2;\n const cy = video.videoHeight / 2;\n\n // ✅ CSS: width: 50% → radius = 25%\n const rx = video.videoWidth * 0.25;\n const ry = rx * (6 / 5); // aspect-ratio: 5/6\n\n // 1️⃣ Yuzning 4 ta chekkasi oval ichida bo'lishi kerak\n const points = [\n { x: box.x, y: box.y + box.height / 2 }, // chap\n { x: box.x + box.width, y: box.y + box.height / 2 }, // o'ng\n { x: box.x + box.width / 2, y: box.y }, // tepa\n { x: box.x + box.width / 2, y: box.y + box.height }, // past\n ];\n\n const inside = points.every((p) => {\n const v = Math.pow(p.x - cx, 2) / Math.pow(rx, 2) + Math.pow(p.y - cy, 2) / Math.pow(ry, 2);\n return v <= 1;\n });\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // 2️⃣ Yuz ovalni yaxshi to'ldirishi kerak (70-90%)\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n // Juda uzoq\n if (fillRatio < 0.4) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n // Juda yaqin\n if (fillRatio > 0.59) {\n this.faceInsideStatus.set('VERY_CLOSE');\n return false;\n }\n\n this.faceInsideStatus.set('VALID');\n return true;\n }\n\n private dist(a: any, b: any) {\n return Math.hypot(a.x - b.x, a.y - b.y);\n }\n\n private eyeEAR(eye: faceapi.Point[]) {\n return (\n (this.dist(eye[1], eye[5]) + this.dist(eye[2], eye[4])) / (2 * this.dist(eye[0], eye[3]))\n );\n }\n\n private isBlink(lm: faceapi.FaceLandmarks68) {\n const left = this.eyeEAR(lm.getLeftEye());\n const right = this.eyeEAR(lm.getRightEye());\n const avg = (left + right) / 2;\n\n if (this.prevBlinkAvg === 0 || Math.abs(avg - this.prevBlinkAvg) < 0.01) {\n this.prevBlinkAvg = avg;\n return false;\n }\n\n this.prevBlinkAvg = avg;\n this.blinkCount++;\n return this.blinkCount > 2;\n }\n\n private isMouthOpen(lm: faceapi.FaceLandmarks68) {\n const mouth = lm.getMouth();\n return this.dist(mouth[13], mouth[19]) / this.dist(mouth[0], mouth[6]) > 0.4;\n }\n\n private isHeadMoved(lm: faceapi.FaceLandmarks68) {\n const nose = lm.getNose()[3];\n if (!this.prevNoseX) {\n this.prevNoseX = nose.x;\n return false;\n }\n const moved = Math.abs(nose.x - this.prevNoseX) > 30;\n\n this.prevNoseX = nose.x;\n return moved;\n }\n\n // ---------- MAIN CHECK ----------\n\n async process(video: HTMLVideoElement): Promise<boolean> {\n const result = await faceapi\n .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())\n .withFaceLandmarks();\n\n if (!result) {\n this.faceInsideStatus.set('NO_FACE');\n return false;\n }\n\n // 👇 OVAL CHECK\n const insideOval = this.isFaceInsideOval(result.detection.box, video);\n\n if (!insideOval) {\n if (this.step() === 'HOLD') {\n this.holdStart = Date.now();\n }\n return false;\n }\n\n const lm = result.landmarks;\n\n if (this.step() === 'BLINK' && this.isBlink(lm)) {\n this.step.set('MOUTH');\n } else if (this.step() === 'MOUTH' && this.isMouthOpen(lm)) {\n this.step.set('HEAD');\n } else if (this.step() === 'HEAD' && this.isHeadMoved(lm)) {\n this.step.set('HOLD');\n this.holdStart = Date.now();\n } else if (this.step() === 'HOLD') {\n if (!this.holdStart) this.holdStart = Date.now();\n if (Date.now() - this.holdStart > 3000) {\n this.step.set('DONE');\n return true; // 📸 CAPTURE SIGNAL\n }\n }\n\n return false;\n }\n}\n","import {\n Component,\n ElementRef,\n ViewChild,\n OnInit,\n computed,\n output,\n inject,\n PLATFORM_ID,\n} from '@angular/core';\nimport { LivenessService } from './liveness.service';\nimport { isPlatformBrowser, NgClass } from '@angular/common';\n\n@Component({\n selector: 'ngx-face-liveness',\n imports: [NgClass],\n template: `\n <div class=\"camera-wrapper\">\n <video #video autoplay muted playsinline class=\"camera-video\"></video>\n\n <!-- Overlay -->\n <div class=\"overlay\">\n <div class=\"oval-mask\" [ngClass]=\"{ 'border-red-500!': isNotValidOval() }\"></div>\n <p class=\"hint\">{{ stepText() }}</p>\n </div>\n </div>\n `,\n styleUrls: ['./face-liveness.scss'],\n})\nexport class NgxFaceLiveness implements OnInit {\n private platformId = inject(PLATFORM_ID);\n private isBrowser = isPlatformBrowser(this.platformId);\n\n @ViewChild('video') videoRef!: ElementRef<HTMLVideoElement>;\n intervalId: any;\n\n capturedImage = output<Blob>();\n\n constructor(private liveness: LivenessService) {}\n\n async ngOnInit() {\n if (!this.isBrowser) return;\n\n await this.liveness.loadModels();\n await this.start();\n }\n\n currentStep = computed(() => this.liveness.currentStep());\n currentFaceInsideStatus = computed(() => this.liveness.currentFaceInsideStatus());\n isNotValidOval = computed(\n () =>\n this.currentFaceInsideStatus() === 'OUTSIDE_OVAL' ||\n this.currentFaceInsideStatus() === 'NO_FACE',\n );\n stepText = computed(() => {\n const currentFaceStatus = this.currentFaceInsideStatus();\n\n if (currentFaceStatus === 'NO_FACE') {\n return '❌ Yuz aniqlanmadi, iltimos, kameraga qarang';\n }\n if (currentFaceStatus === 'OUTSIDE_OVAL') {\n return '📐 Iltimos, yuzingizni oval ichiga joylashtiring';\n }\n if (currentFaceStatus === 'COME_CLOSE') {\n return '🔍 Iltimos, kameraga yaqinroq turing';\n }\n if (currentFaceStatus === 'VERY_CLOSE') {\n return '📷 Juda yaqin, kamerani orqaroq oling';\n }\n\n switch (this.currentStep()) {\n case 'BLINK':\n return '👁 Ko‘zingizni yumib oching(kamida 2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming (kamida yarim ochish kerak)';\n case 'HEAD':\n return '↔️ Boshni chapga yoki o‘ngga burang';\n case 'HOLD':\n return '✋ Barqaror turing (2 soniya)';\n default:\n return '✅ Tayyor!';\n }\n });\n\n async start() {\n this.liveness.reset();\n await this.openCamera();\n\n this.intervalId = setInterval(async () => {\n const done = await this.liveness.process(this.videoRef.nativeElement);\n\n if (done) {\n clearInterval(this.intervalId);\n const blob = await this.capture();\n this.sendToBackend(blob);\n }\n }, 300);\n }\n\n async openCamera() {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: 'user' },\n });\n this.videoRef.nativeElement.srcObject = stream;\n }\n\n async capture(): Promise<Blob> {\n const video = this.videoRef.nativeElement;\n const canvas = document.createElement('canvas');\n\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n\n canvas.getContext('2d')!.drawImage(video, 0, 0);\n\n return new Promise((res) => canvas.toBlob((b) => res(b!), 'image/jpeg', 0.9));\n }\n\n sendToBackend(blob: Blob) {\n this.capturedImage.emit(blob);\n console.log(blob);\n\n // const fd = new FormData();\n // fd.append('file', blob, 'face.jpg');\n // this.http.post('/api/face/verify', fd).subscribe();\n }\n\n ngOnDestroy(): void {\n if (!this.isBrowser) return;\n\n this.cleanup();\n }\n\n private cleanup() {\n // 1️⃣ Interval\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n\n // 2️⃣ Kamera\n const video = this.videoRef?.nativeElement;\n if (video) {\n video.pause();\n\n const stream = video.srcObject as MediaStream | null;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n video.srcObject = null;\n }\n\n // 3️⃣ Service state\n this.liveness.reset();\n }\n}\n","/*\r\n * Public API Surface of ngx-face-id\r\n */\r\n\r\nexport * from './lib/face-liveness/face-liveness';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utamuratov-ngx-face-id.mjs","sources":["../../../projects/ngx-face-id/src/lib/face-liveness/liveness.service.ts","../../../projects/ngx-face-id/src/lib/face-liveness/face-liveness.ts","../../../projects/ngx-face-id/src/public-api.ts","../../../projects/ngx-face-id/src/utamuratov-ngx-face-id.ts"],"sourcesContent":["import { computed, Injectable, signal } from '@angular/core';\nimport * as faceapi from 'face-api.js';\n\ntype Step =\n // | 'NO_FACE'\n // | 'OUTSIDE_OVAL'\n // | 'COME_CLOSE'\n // | 'VERY_CLOSE'\n 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';\n\ntype FaceInside = 'NO_FACE' | 'OUTSIDE_OVAL' | 'COME_CLOSE' | 'VERY_CLOSE' | 'VALID';\n\n@Injectable({ providedIn: 'root' })\nexport class LivenessService {\n private step = signal<Step>('BLINK');\n private faceInsideStatus = signal<FaceInside>('OUTSIDE_OVAL');\n currentStep = computed(() => this.step());\n currentFaceInsideStatus = computed(() => this.faceInsideStatus());\n\n private prevBlinkAvg = 0;\n private blinkCount = 0;\n private prevNoseX?: number;\n private holdStart?: number;\n\n async loadModels() {\n const MODEL_URL = '/models';\n await Promise.all([\n faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),\n faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),\n faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),\n ]);\n }\n\n reset() {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n this.step.set('BLINK');\n this.blinkCount = 0;\n this.prevBlinkAvg = 0;\n this.prevNoseX = undefined;\n this.holdStart = undefined;\n }\n\n // ---------- HELPERS ----------\n\n private isFaceInsideOval(box: faceapi.Box, video: HTMLVideoElement): boolean {\n const cx = video.videoWidth / 2;\n const cy = video.videoHeight / 2;\n\n // ✅ CSS: width: 50% → radius = 25%\n const rx = video.videoWidth * 0.25;\n const ry = rx * (6 / 5); // aspect-ratio: 5/6\n\n // 1️⃣ Yuzning 4 ta chekkasi oval ichida bo'lishi kerak\n const points = [\n { x: box.x, y: box.y + box.height / 2 }, // chap\n { x: box.x + box.width, y: box.y + box.height / 2 }, // o'ng\n { x: box.x + box.width / 2, y: box.y }, // tepa\n { x: box.x + box.width / 2, y: box.y + box.height }, // past\n ];\n\n const inside = points.every((p) => {\n const v = Math.pow(p.x - cx, 2) / Math.pow(rx, 2) + Math.pow(p.y - cy, 2) / Math.pow(ry, 2);\n return v <= 1;\n });\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // 2️⃣ Yuz ovalni yaxshi to'ldirishi kerak (70-90%)\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n // Juda uzoq\n if (fillRatio < 0.4) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n // Juda yaqin\n if (fillRatio > 0.59) {\n this.faceInsideStatus.set('VERY_CLOSE');\n return false;\n }\n\n this.faceInsideStatus.set('VALID');\n return true;\n }\n\n private dist(a: any, b: any) {\n return Math.hypot(a.x - b.x, a.y - b.y);\n }\n\n private eyeEAR(eye: faceapi.Point[]) {\n return (\n (this.dist(eye[1], eye[5]) + this.dist(eye[2], eye[4])) / (2 * this.dist(eye[0], eye[3]))\n );\n }\n\n private isBlink(lm: faceapi.FaceLandmarks68) {\n const left = this.eyeEAR(lm.getLeftEye());\n const right = this.eyeEAR(lm.getRightEye());\n const avg = (left + right) / 2;\n\n if (this.prevBlinkAvg === 0 || Math.abs(avg - this.prevBlinkAvg) < 0.01) {\n this.prevBlinkAvg = avg;\n return false;\n }\n\n this.prevBlinkAvg = avg;\n this.blinkCount++;\n return this.blinkCount > 2;\n }\n\n private isMouthOpen(lm: faceapi.FaceLandmarks68) {\n const mouth = lm.getMouth();\n return this.dist(mouth[13], mouth[19]) / this.dist(mouth[0], mouth[6]) > 0.4;\n }\n\n private isHeadMoved(lm: faceapi.FaceLandmarks68) {\n const nose = lm.getNose()[3];\n if (!this.prevNoseX) {\n this.prevNoseX = nose.x;\n return false;\n }\n const moved = Math.abs(nose.x - this.prevNoseX) > 30;\n\n this.prevNoseX = nose.x;\n return moved;\n }\n\n // ---------- MAIN CHECK ----------\n\n async process(video: HTMLVideoElement): Promise<boolean> {\n const result = await faceapi\n .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())\n .withFaceLandmarks();\n\n if (!result) {\n this.faceInsideStatus.set('NO_FACE');\n return false;\n }\n\n // 👇 OVAL CHECK\n const insideOval = this.isFaceInsideOval(result.detection.box, video);\n\n if (!insideOval) {\n if (this.step() === 'HOLD') {\n this.holdStart = Date.now();\n }\n return false;\n }\n\n const lm = result.landmarks;\n\n if (this.step() === 'BLINK' && this.isBlink(lm)) {\n this.step.set('MOUTH');\n } else if (this.step() === 'MOUTH' && this.isMouthOpen(lm)) {\n this.step.set('HEAD');\n } else if (this.step() === 'HEAD' && this.isHeadMoved(lm)) {\n this.step.set('HOLD');\n this.holdStart = Date.now();\n } else if (this.step() === 'HOLD') {\n if (!this.holdStart) this.holdStart = Date.now();\n if (Date.now() - this.holdStart > 3000) {\n this.step.set('DONE');\n return true; // 📸 CAPTURE SIGNAL\n }\n }\n\n return false;\n }\n}\n","import {\n Component,\n ElementRef,\n ViewChild,\n OnInit,\n computed,\n output,\n inject,\n PLATFORM_ID,\n signal,\n} from '@angular/core';\nimport { LivenessService } from './liveness.service';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Component({\n selector: 'ngx-face-liveness',\n template: `\n <div class=\"camera-wrapper\">\n @if (capturesImageSrc()) {\n <img [src]=\"capturesImageSrc()\" alt=\"Captured Image\" class=\"captured-image\" />\n }\n <video #video autoplay muted playsinline class=\"camera-video\"></video>\n\n <!-- Overlay -->\n <div class=\"overlay\">\n <div class=\"oval-mask\" [style.borderColor]=\"isNotValidOval() ? '#fb2c36' : '#65a0f8'\"></div>\n <p class=\"hint\">{{ stepText() }}</p>\n </div>\n </div>\n `,\n styleUrls: ['./face-liveness.scss'],\n})\nexport class NgxFaceLiveness implements OnInit {\n private platformId = inject(PLATFORM_ID);\n private isBrowser = isPlatformBrowser(this.platformId);\n\n @ViewChild('video') videoRef!: ElementRef<HTMLVideoElement>;\n intervalId: any;\n\n capturedImage = output<Blob>();\n capturesImageSrc = signal<string | null>(null);\n\n constructor(private liveness: LivenessService) {}\n\n async ngOnInit() {\n if (!this.isBrowser) return;\n\n await this.liveness.loadModels();\n await this.start();\n }\n\n currentStep = computed(() => this.liveness.currentStep());\n currentFaceInsideStatus = computed(() => this.liveness.currentFaceInsideStatus());\n isNotValidOval = computed(\n () =>\n this.currentFaceInsideStatus() === 'OUTSIDE_OVAL' ||\n this.currentFaceInsideStatus() === 'NO_FACE',\n );\n stepText = computed(() => {\n const currentFaceStatus = this.currentFaceInsideStatus();\n\n if (currentFaceStatus === 'NO_FACE') {\n return '❌ Yuz aniqlanmadi, iltimos, kameraga qarang';\n }\n if (currentFaceStatus === 'OUTSIDE_OVAL') {\n return '📐 Iltimos, yuzingizni oval ichiga joylashtiring';\n }\n if (currentFaceStatus === 'COME_CLOSE') {\n return '🔍 Iltimos, kameraga yaqinroq turing';\n }\n if (currentFaceStatus === 'VERY_CLOSE') {\n return '📷 Juda yaqin, kamerani orqaroq oling';\n }\n\n switch (this.currentStep()) {\n case 'BLINK':\n return '👁 Ko‘zingizni yumib oching(kamida 2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming (kamida yarim ochish kerak)';\n case 'HEAD':\n return '↔️ Boshni chapga yoki o‘ngga burang';\n case 'HOLD':\n return '✋ Barqaror turing (2 soniya)';\n default:\n return '✅ Tayyor!';\n }\n });\n\n async start() {\n this.liveness.reset();\n await this.openCamera();\n\n this.intervalId = setInterval(async () => {\n const done = await this.liveness.process(this.videoRef.nativeElement);\n\n if (done) {\n clearInterval(this.intervalId);\n const blob = await this.capture();\n this.sendToBackend(blob);\n }\n }, 300);\n }\n\n async openCamera() {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: 'user' },\n });\n this.videoRef.nativeElement.srcObject = stream;\n }\n\n async capture(): Promise<Blob> {\n const video = this.videoRef.nativeElement;\n const canvas = document.createElement('canvas');\n\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n\n canvas.getContext('2d')!.drawImage(video, 0, 0);\n\n return new Promise((res) => canvas.toBlob((b) => res(b!), 'image/jpeg', 0.9));\n }\n\n sendToBackend(blob: Blob) {\n this.capturedImage.emit(blob);\n this.capturesImageSrc.set(URL.createObjectURL(blob));\n console.log(blob);\n\n // const fd = new FormData();\n // fd.append('file', blob, 'face.jpg');\n // this.http.post('/api/face/verify', fd).subscribe();\n }\n\n ngOnDestroy(): void {\n if (!this.isBrowser) return;\n\n this.cleanup();\n }\n\n private cleanup() {\n // 1️⃣ Interval\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n\n // 2️⃣ Kamera\n const video = this.videoRef?.nativeElement;\n if (video) {\n video.pause();\n\n const stream = video.srcObject as MediaStream | null;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n video.srcObject = null;\n }\n\n // 3️⃣ Service state\n this.liveness.reset();\n }\n}\n","/*\r\n * Public API Surface of ngx-face-id\r\n */\r\n\r\nexport * from './lib/face-liveness/face-liveness';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -32,6 +32,7 @@ declare class NgxFaceLiveness implements OnInit {
|
|
|
32
32
|
videoRef: ElementRef<HTMLVideoElement>;
|
|
33
33
|
intervalId: any;
|
|
34
34
|
capturedImage: _angular_core.OutputEmitterRef<Blob>;
|
|
35
|
+
capturesImageSrc: _angular_core.WritableSignal<string | null>;
|
|
35
36
|
constructor(liveness: LivenessService);
|
|
36
37
|
ngOnInit(): Promise<void>;
|
|
37
38
|
currentStep: _angular_core.Signal<"BLINK" | "MOUTH" | "HEAD" | "HOLD" | "DONE">;
|