'training', 'message' => 'Memulai training model SVM...', ], 3600); $approvedUsers = DB::table('data_wajah') ->where('is_verified', StatusVerifikasiWajah::APPROVED) ->pluck('id_user') ->toArray(); if (count($approvedUsers) === 0) { Log::info("Tidak ada user approved. Skip training."); return; } $approvedStr = array_map('strval', $approvedUsers); try { $response = Http::timeout(600) ->withHeaders([ 'X-API-Key' => config('services.flask.api_key'), ]) ->post(config('services.flask.url') . '/train-model', [ 'approved_user_ids' => $approvedStr, ]); if (!$response->successful()) { throw new \Exception("Flask API error: HTTP {$response->status()} - " . $response->body()); } $output = $response->json(); if (!isset($output['status']) || $output['status'] !== 'success') { throw new \Exception("Training error: " . ($output['message'] ?? 'Unknown')); } $totalUsers = $output['total_users'] ?? 0; $testAcc = $output['test_accuracy'] ?? 0; Log::info("Training model global selesai. Total user: {$totalUsers}"); Cache::put('face_training_status', [ 'phase' => 'done', 'message' => "Training selesai! {$totalUsers} user, Akurasi: " . round($testAcc * 100, 2) . '%', ], 300); app(\App\Services\NotifikasiService::class)->kirimKeRole( 'hrd', 'pengumuman', 'Training Model Selesai', "Sistem telah berhasil memperbarui model AI Face Recognition untuk {$totalUsers} karyawan." ); } catch (\Exception $e) { Log::error("Training model global GAGAL: " . $e->getMessage()); Cache::put('face_training_status', [ 'phase' => 'error', 'message' => 'Training gagal: ' . $e->getMessage(), ], 300); app(\App\Services\NotifikasiService::class)->kirimKeRole( 'hrd', 'pengumuman', 'Training Model Gagal', 'Terjadi kesalahan saat melatih ulang model AI. Silakan cek log server.' ); } } }