172 lines
6.2 KiB
PHP
172 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use App\Services\FaceRecognitionService;
|
|
use Illuminate\Support\Facades\Log;
|
|
use App\Enums\StatusVerifikasiWajah;
|
|
|
|
class FaceEnrollmentController extends Controller
|
|
{
|
|
protected $faceService;
|
|
|
|
public function __construct(FaceRecognitionService $faceService)
|
|
{
|
|
$this->faceService = $faceService;
|
|
}
|
|
|
|
public function enrollFace(Request $request)
|
|
{
|
|
$validator = \Validator::make($request->all(), [
|
|
'video_wajah' => 'required|file|mimetypes:video/mp4,video/quicktime,video/x-msvideo,video/3gpp,video/x-matroska|max:51200',
|
|
], [
|
|
'video_wajah.required' => 'File video wajah wajib diupload.',
|
|
'video_wajah.file' => 'Data yang dikirim bukan file yang valid.',
|
|
'video_wajah.mimetypes' => 'Format video tidak didukung. Gunakan MP4, MOV, atau AVI.',
|
|
'video_wajah.max' => 'Ukuran video terlalu besar (maksimal 50MB).',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
Log::warning('Face Enrollment Validation Failed', [
|
|
'errors' => $validator->errors()->toArray(),
|
|
'has_file' => $request->hasFile('video_wajah'),
|
|
'file_size' => $request->hasFile('video_wajah')
|
|
? $request->file('video_wajah')->getSize()
|
|
: null,
|
|
'file_mime' => $request->hasFile('video_wajah')
|
|
? $request->file('video_wajah')->getMimeType()
|
|
: null,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => $validator->errors()->first(),
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
try {
|
|
$user = $request->user();
|
|
$video = $request->file('video_wajah');
|
|
|
|
$result = $this->faceService->enrollFace($user->id, $video);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => $result['message'],
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('Face Enrollment Error: ' . $e->getMessage());
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Terjadi kesalahan sistem: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function getFaceStatus(Request $request)
|
|
{
|
|
$user = $request->user();
|
|
|
|
$dataWajah = \DB::table('data_wajah')->where('id_user', $user->id)->first();
|
|
|
|
$status = 'not_registered';
|
|
if ($user->is_face_registered) {
|
|
$status = 'pending';
|
|
if ($dataWajah && $dataWajah->is_verified == StatusVerifikasiWajah::APPROVED) {
|
|
$status = 'verified';
|
|
} elseif ($dataWajah && $dataWajah->is_verified == StatusVerifikasiWajah::REJECTED) {
|
|
$status = 'rejected';
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'status' => $status,
|
|
'is_registered' => (bool) $user->is_face_registered
|
|
]
|
|
]);
|
|
}
|
|
|
|
public function verifyFace(Request $request)
|
|
{
|
|
$request->validate([
|
|
'file_wajah' => 'required|file|max:20480',
|
|
'tipe' => 'nullable|string|in:presensi,test',
|
|
]);
|
|
|
|
$tipe = $request->input('tipe', 'presensi');
|
|
|
|
try {
|
|
set_time_limit(0);
|
|
|
|
$user = $request->user();
|
|
|
|
$file = $request->file('file_wajah');
|
|
$result = $this->faceService->verifyFace($user->id, $file);
|
|
|
|
$predictedUserId = $result['predicted_user'] ?? null;
|
|
$predictedName = null;
|
|
if ($predictedUserId && is_numeric($predictedUserId)) {
|
|
$predictedUser = \DB::table('users')
|
|
->where('id', $predictedUserId)
|
|
->value('nama_lengkap');
|
|
$predictedName = $predictedUser ?? "User #{$predictedUserId}";
|
|
} elseif ($predictedUserId === 'unknown') {
|
|
$predictedName = 'Tidak Dikenal';
|
|
}
|
|
|
|
$skorSvm = isset($result['svm_df']) ? round(max(-9999.9999, min(9999.9999, (float) $result['svm_df'])), 4) : null;
|
|
$skorKepercayaan = isset($result['confidence']) ? round(max(-9999.9999, min(9999.9999, (float) $result['confidence'])), 4) : null;
|
|
|
|
\DB::table('log_verifikasi_wajah')->insert([
|
|
'id_user' => $user->id,
|
|
'skor_kepercayaan' => $skorKepercayaan,
|
|
'skor_svm' => $skorSvm,
|
|
'jarak_normalisasi'=> null,
|
|
'status_verifikasi'=> $result['verification_status'] ?? null,
|
|
'apakah_cocok' => $result['verified'] ?? false,
|
|
'skor_blur' => $result['blur_score'] ?? null,
|
|
'tipe' => $tipe,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
$isMatch = $result['verified'] ?? false;
|
|
$message = $isMatch
|
|
? 'Wajah terverifikasi'
|
|
: ($predictedName && $predictedName !== 'Tidak Dikenal' ? "Wajah dikenali sebagai {$predictedName}, bukan Anda." : 'Wajah tidak cocok dengan data Anda.');
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => $message,
|
|
'data' => array_merge($result, [
|
|
'predicted_name' => $predictedName,
|
|
]),
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
if (isset($user)) {
|
|
\DB::table('log_verifikasi_wajah')->insert([
|
|
'id_user' => $user->id,
|
|
'skor_kepercayaan' => 0,
|
|
'status_verifikasi' => 'ERROR',
|
|
'apakah_cocok' => false,
|
|
'tipe' => $tipe ?? 'presensi',
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Verifikasi Gagal: ' . $e->getMessage()
|
|
], 400);
|
|
}
|
|
}
|
|
}
|