@utamuratov/ngx-face-id 0.5.0 → 0.6.0
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.
|
@@ -4,7 +4,7 @@ import { isPlatformBrowser } from '@angular/common';
|
|
|
4
4
|
import * as faceapi from 'face-api.js';
|
|
5
5
|
|
|
6
6
|
class LivenessService {
|
|
7
|
-
step = signal('
|
|
7
|
+
step = signal('START', ...(ngDevMode ? [{ debugName: "step" }] : []));
|
|
8
8
|
faceInsideStatus = signal('OUTSIDE_OVAL', ...(ngDevMode ? [{ debugName: "faceInsideStatus" }] : []));
|
|
9
9
|
currentStep = computed(() => this.step(), ...(ngDevMode ? [{ debugName: "currentStep" }] : []));
|
|
10
10
|
currentFaceInsideStatus = computed(() => this.faceInsideStatus(), ...(ngDevMode ? [{ debugName: "currentFaceInsideStatus" }] : []));
|
|
@@ -22,7 +22,7 @@ class LivenessService {
|
|
|
22
22
|
}
|
|
23
23
|
reset() {
|
|
24
24
|
this.faceInsideStatus.set('OUTSIDE_OVAL');
|
|
25
|
-
this.step.set('
|
|
25
|
+
this.step.set('START');
|
|
26
26
|
this.blinkCount = 0;
|
|
27
27
|
this.prevBlinkAvg = 0;
|
|
28
28
|
this.prevNoseX = undefined;
|
|
@@ -101,33 +101,41 @@ class LivenessService {
|
|
|
101
101
|
}
|
|
102
102
|
// ---------- MAIN CHECK ----------
|
|
103
103
|
async process(video) {
|
|
104
|
+
const step = this.step();
|
|
104
105
|
const result = await faceapi
|
|
105
106
|
.detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())
|
|
106
107
|
.withFaceLandmarks();
|
|
107
108
|
if (!result) {
|
|
108
|
-
|
|
109
|
+
if (step === 'START') {
|
|
110
|
+
this.faceInsideStatus.set('NO_FACE');
|
|
111
|
+
}
|
|
109
112
|
return false;
|
|
110
113
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
this.
|
|
114
|
+
if (step === 'START') {
|
|
115
|
+
// 👇 OVAL CHECK
|
|
116
|
+
const insideOval = this.isFaceInsideOval(result.detection.box, video);
|
|
117
|
+
if (!insideOval) {
|
|
118
|
+
if (this.step() === 'HOLD') {
|
|
119
|
+
this.holdStart = Date.now();
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
116
122
|
}
|
|
117
|
-
return false;
|
|
118
123
|
}
|
|
119
124
|
const lm = result.landmarks;
|
|
120
|
-
if (
|
|
125
|
+
if (step === 'START') {
|
|
126
|
+
this.step.set('BLINK');
|
|
127
|
+
}
|
|
128
|
+
else if (step === 'BLINK' && this.isBlink(lm)) {
|
|
121
129
|
this.step.set('MOUTH');
|
|
122
130
|
}
|
|
123
|
-
else if (
|
|
131
|
+
else if (step === 'MOUTH' && this.isMouthOpen(lm)) {
|
|
124
132
|
this.step.set('HEAD');
|
|
125
133
|
}
|
|
126
|
-
else if (
|
|
134
|
+
else if (step === 'HEAD' && this.isHeadMoved(lm)) {
|
|
127
135
|
this.step.set('HOLD');
|
|
128
136
|
this.holdStart = Date.now();
|
|
129
137
|
}
|
|
130
|
-
else if (
|
|
138
|
+
else if (step === 'HOLD') {
|
|
131
139
|
if (!this.holdStart)
|
|
132
140
|
this.holdStart = Date.now();
|
|
133
141
|
if (Date.now() - this.holdStart > 3000) {
|
|
@@ -149,6 +157,8 @@ class NgxFaceLiveness {
|
|
|
149
157
|
liveness;
|
|
150
158
|
platformId = inject(PLATFORM_ID);
|
|
151
159
|
isBrowser = isPlatformBrowser(this.platformId);
|
|
160
|
+
loadingResourses = signal(true, ...(ngDevMode ? [{ debugName: "loadingResourses" }] : []));
|
|
161
|
+
loadingMessage = signal('Kamera yuklanmoqda...', ...(ngDevMode ? [{ debugName: "loadingMessage" }] : []));
|
|
152
162
|
videoRef;
|
|
153
163
|
intervalId;
|
|
154
164
|
capturedImage = output();
|
|
@@ -169,13 +179,13 @@ class NgxFaceLiveness {
|
|
|
169
179
|
stepText = computed(() => {
|
|
170
180
|
const currentFaceStatus = this.currentFaceInsideStatus();
|
|
171
181
|
if (currentFaceStatus === 'NO_FACE') {
|
|
172
|
-
return '❌ Yuz aniqlanmadi,
|
|
182
|
+
return '❌ Yuz aniqlanmadi, kameraga qarang';
|
|
173
183
|
}
|
|
174
184
|
if (currentFaceStatus === 'OUTSIDE_OVAL') {
|
|
175
|
-
return '📐
|
|
185
|
+
return '📐 Yuzingizni oval ichiga joylashtiring';
|
|
176
186
|
}
|
|
177
187
|
if (currentFaceStatus === 'COME_CLOSE') {
|
|
178
|
-
return '🔍
|
|
188
|
+
return '🔍 Kameraga yaqinroq turing';
|
|
179
189
|
}
|
|
180
190
|
if (currentFaceStatus === 'VERY_CLOSE') {
|
|
181
191
|
return '📷 Juda yaqin, kamerani orqaroq oling';
|
|
@@ -210,6 +220,7 @@ class NgxFaceLiveness {
|
|
|
210
220
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
211
221
|
const videoDevices = devices.filter((d) => d.kind === 'videoinput');
|
|
212
222
|
if (!videoDevices.length) {
|
|
223
|
+
this.loadingMessage.set('Kamera qurilmasi topilmadi!');
|
|
213
224
|
throw new Error('No video devices found');
|
|
214
225
|
}
|
|
215
226
|
// USB yoki default camera tanlash
|
|
@@ -219,6 +230,7 @@ class NgxFaceLiveness {
|
|
|
219
230
|
}, // birinchi topilgan kamera
|
|
220
231
|
});
|
|
221
232
|
this.videoRef.nativeElement.srcObject = stream;
|
|
233
|
+
this.loadingResourses.set(false);
|
|
222
234
|
}
|
|
223
235
|
catch (err) {
|
|
224
236
|
console.error('Cannot access camera:', err);
|
|
@@ -270,7 +282,7 @@ class NgxFaceLiveness {
|
|
|
270
282
|
}
|
|
271
283
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NgxFaceLiveness, deps: [{ token: LivenessService }], target: i0.ɵɵFactoryTarget.Component });
|
|
272
284
|
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: `
|
|
273
|
-
<div class="camera-wrapper">
|
|
285
|
+
<div class="camera-wrapper" [hidden]="loadingResourses()">
|
|
274
286
|
@if (capturesImageSrc()) {
|
|
275
287
|
<img [src]="capturesImageSrc()" alt="Captured Image" class="captured-image" />
|
|
276
288
|
}
|
|
@@ -282,12 +294,15 @@ class NgxFaceLiveness {
|
|
|
282
294
|
<p class="hint">{{ stepText() }}</p>
|
|
283
295
|
</div>
|
|
284
296
|
</div>
|
|
285
|
-
|
|
297
|
+
@if (loadingResourses()) {
|
|
298
|
+
<p class="loading-text">{{ loadingMessage() }}</p>
|
|
299
|
+
}
|
|
300
|
+
`, isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;justify-content:center;height:100%;min-height:640px;padding:1rem}.camera-wrapper{width:100%;max-width:640px;min-height:480px;overflow:hidden;position:relative;border-radius:12px;border-radius:1rem;background:#65a0f8}@media(max-width:400px){.camera-wrapper{min-height:240px}}.camera-video{width:100%;height:auto;max-height:100%;object-fit:contain;transform:scaleX(-1)}.overlay{position:absolute;z-index:3;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{height:90%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{color:#fff;font-size:18px;font-weight:500;line-height:1.3;width:250px;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;z-index:2;transform:scaleX(-1)}.loading-text{font-size:18px;font-weight:500}\n"] });
|
|
286
301
|
}
|
|
287
302
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NgxFaceLiveness, decorators: [{
|
|
288
303
|
type: Component,
|
|
289
304
|
args: [{ selector: 'ngx-face-liveness', template: `
|
|
290
|
-
<div class="camera-wrapper">
|
|
305
|
+
<div class="camera-wrapper" [hidden]="loadingResourses()">
|
|
291
306
|
@if (capturesImageSrc()) {
|
|
292
307
|
<img [src]="capturesImageSrc()" alt="Captured Image" class="captured-image" />
|
|
293
308
|
}
|
|
@@ -299,7 +314,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
299
314
|
<p class="hint">{{ stepText() }}</p>
|
|
300
315
|
</div>
|
|
301
316
|
</div>
|
|
302
|
-
|
|
317
|
+
@if (loadingResourses()) {
|
|
318
|
+
<p class="loading-text">{{ loadingMessage() }}</p>
|
|
319
|
+
}
|
|
320
|
+
`, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;justify-content:center;height:100%;min-height:640px;padding:1rem}.camera-wrapper{width:100%;max-width:640px;min-height:480px;overflow:hidden;position:relative;border-radius:12px;border-radius:1rem;background:#65a0f8}@media(max-width:400px){.camera-wrapper{min-height:240px}}.camera-video{width:100%;height:auto;max-height:100%;object-fit:contain;transform:scaleX(-1)}.overlay{position:absolute;z-index:3;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{height:90%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{color:#fff;font-size:18px;font-weight:500;line-height:1.3;width:250px;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;z-index:2;transform:scaleX(-1)}.loading-text{font-size:18px;font-weight:500}\n"] }]
|
|
303
321
|
}], ctorParameters: () => [{ type: LivenessService }], propDecorators: { videoRef: [{
|
|
304
322
|
type: ViewChild,
|
|
305
323
|
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 = '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 vw = video.videoWidth;\n const vh = video.videoHeight;\n\n // Oval markazi\n const cx = vw / 2;\n const cy = vh / 2;\n\n // Oval radius\n const ry = vh * 0.45; // height = 90%\n const rx = ry * (5 / 6); // aspect-ratio = 5/6\n\n // Mirror x for CSS scaleX(-1)\n const mirrorX = (x: number) => vw - x;\n\n // Face edge points\n const points = [\n { x: mirrorX(box.x), y: box.y + box.height / 2 }, // left\n { x: mirrorX(box.x + box.width), y: box.y + box.height / 2 }, // right\n { x: mirrorX(box.x + box.width / 2), y: box.y }, // top\n { x: mirrorX(box.x + box.width / 2), y: box.y + box.height }, // bottom\n ];\n\n const inside = points.every(\n (p) => Math.pow((p.x - cx) / rx, 2) + Math.pow((p.y - cy) / ry, 2) <= 1,\n );\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // Fill ratio\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n if (fillRatio < 0.42) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n if (fillRatio > 0.6) {\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(2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming';\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 try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const videoDevices = devices.filter((d) => d.kind === 'videoinput');\n\n if (!videoDevices.length) {\n throw new Error('No video devices found');\n }\n\n // USB yoki default camera tanlash\n const stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: videoDevices[0].deviceId,\n }, // birinchi topilgan kamera\n });\n\n this.videoRef.nativeElement.srcObject = stream;\n } catch (err) {\n console.error('Cannot access camera:', err);\n }\n\n // const stream = await navigator.mediaDevices.getUserMedia({\n // video: { facingMode: 'user', aspectRatio: 3 / 4, width: { min: 480 }, height: { min: 640 } },\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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"}
|
|
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 = 'START' | '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>('START');\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('START');\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 vw = video.videoWidth;\n const vh = video.videoHeight;\n\n // Oval markazi\n const cx = vw / 2;\n const cy = vh / 2;\n\n // Oval radius\n const ry = vh * 0.45; // height = 90%\n const rx = ry * (5 / 6); // aspect-ratio = 5/6\n\n // Mirror x for CSS scaleX(-1)\n const mirrorX = (x: number) => vw - x;\n\n // Face edge points\n const points = [\n { x: mirrorX(box.x), y: box.y + box.height / 2 }, // left\n { x: mirrorX(box.x + box.width), y: box.y + box.height / 2 }, // right\n { x: mirrorX(box.x + box.width / 2), y: box.y }, // top\n { x: mirrorX(box.x + box.width / 2), y: box.y + box.height }, // bottom\n ];\n\n const inside = points.every(\n (p) => Math.pow((p.x - cx) / rx, 2) + Math.pow((p.y - cy) / ry, 2) <= 1,\n );\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // Fill ratio\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n if (fillRatio < 0.42) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n if (fillRatio > 0.6) {\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 step = this.step();\n\n const result = await faceapi\n .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())\n .withFaceLandmarks();\n\n if (!result) {\n if (step === 'START') {\n this.faceInsideStatus.set('NO_FACE');\n }\n return false;\n }\n\n if (step === 'START') {\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\n const lm = result.landmarks;\n\n if (step === 'START') {\n this.step.set('BLINK');\n } else if (step === 'BLINK' && this.isBlink(lm)) {\n this.step.set('MOUTH');\n } else if (step === 'MOUTH' && this.isMouthOpen(lm)) {\n this.step.set('HEAD');\n } else if (step === 'HEAD' && this.isHeadMoved(lm)) {\n this.step.set('HOLD');\n this.holdStart = Date.now();\n } else if (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\" [hidden]=\"loadingResourses()\">\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 @if (loadingResourses()) {\n <p class=\"loading-text\">{{ loadingMessage() }}</p>\n }\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 loadingResourses = signal(true);\n loadingMessage = signal('Kamera yuklanmoqda...');\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, kameraga qarang';\n }\n if (currentFaceStatus === 'OUTSIDE_OVAL') {\n return '📐 Yuzingizni oval ichiga joylashtiring';\n }\n if (currentFaceStatus === 'COME_CLOSE') {\n return '🔍 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(2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming';\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 try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const videoDevices = devices.filter((d) => d.kind === 'videoinput');\n\n if (!videoDevices.length) {\n this.loadingMessage.set('Kamera qurilmasi topilmadi!');\n throw new Error('No video devices found');\n }\n\n // USB yoki default camera tanlash\n const stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: videoDevices[0].deviceId,\n }, // birinchi topilgan kamera\n });\n\n this.videoRef.nativeElement.srcObject = stream;\n this.loadingResourses.set(false);\n } catch (err) {\n console.error('Cannot access camera:', err);\n }\n\n // const stream = await navigator.mediaDevices.getUserMedia({\n // video: { facingMode: 'user', aspectRatio: 3 / 4, width: { min: 480 }, height: { min: 640 } },\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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { OnInit, ElementRef } from '@angular/core';
|
|
3
3
|
|
|
4
|
-
type Step = 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';
|
|
4
|
+
type Step = 'START' | 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';
|
|
5
5
|
type FaceInside = 'NO_FACE' | 'OUTSIDE_OVAL' | 'COME_CLOSE' | 'VERY_CLOSE' | 'VALID';
|
|
6
6
|
declare class LivenessService {
|
|
7
7
|
private step;
|
|
@@ -29,16 +29,18 @@ declare class NgxFaceLiveness implements OnInit {
|
|
|
29
29
|
private liveness;
|
|
30
30
|
private platformId;
|
|
31
31
|
private isBrowser;
|
|
32
|
+
loadingResourses: _angular_core.WritableSignal<boolean>;
|
|
33
|
+
loadingMessage: _angular_core.WritableSignal<string>;
|
|
32
34
|
videoRef: ElementRef<HTMLVideoElement>;
|
|
33
35
|
intervalId: any;
|
|
34
36
|
capturedImage: _angular_core.OutputEmitterRef<Blob>;
|
|
35
37
|
capturesImageSrc: _angular_core.WritableSignal<string | null>;
|
|
36
38
|
constructor(liveness: LivenessService);
|
|
37
39
|
ngOnInit(): Promise<void>;
|
|
38
|
-
currentStep: _angular_core.Signal<"BLINK" | "MOUTH" | "HEAD" | "HOLD" | "DONE">;
|
|
40
|
+
currentStep: _angular_core.Signal<"START" | "BLINK" | "MOUTH" | "HEAD" | "HOLD" | "DONE">;
|
|
39
41
|
currentFaceInsideStatus: _angular_core.Signal<"NO_FACE" | "OUTSIDE_OVAL" | "COME_CLOSE" | "VERY_CLOSE" | "VALID">;
|
|
40
42
|
isNotValidOval: _angular_core.Signal<boolean>;
|
|
41
|
-
stepText: _angular_core.Signal<"❌ Yuz aniqlanmadi,
|
|
43
|
+
stepText: _angular_core.Signal<"❌ Yuz aniqlanmadi, kameraga qarang" | "📐 Yuzingizni oval ichiga joylashtiring" | "🔍 Kameraga yaqinroq turing" | "📷 Juda yaqin, kamerani orqaroq oling" | "👁 Ko‘zingizni yumib oching(2 marta)" | "🙂 Og‘zingizni ochib yuming" | "↔️ Boshni chapga yoki o‘ngga burang" | "✋ Barqaror turing (2 soniya)" | "✅ Tayyor!">;
|
|
42
44
|
start(): Promise<void>;
|
|
43
45
|
openCamera(): Promise<void>;
|
|
44
46
|
capture(): Promise<Blob>;
|