[ 'keywords' => ['kotor', 'sampah', 'bersih', 'jorok', 'kumuh', 'toilet', 'wc', 'kamar mandi', 'limbah', 'bau'], 'color' => 'red', 'icon' => '๐Ÿงน', 'saran' => [ 'actions' => ['Tambah tempat sampah', 'Jadwal pembersihan rutin', 'Petugas kebersihan tambahan'], 'dampak' => 'Kepuasan meningkat signifikan', 'tip' => 'Tambah tempat sampah & jadwal pembersihan rutin.', ], ], 'Parkir' => [ 'keywords' => ['parkir', 'lahan parkir', 'tempat parkir', 'parkiran', 'motor', 'mobil'], 'color' => 'orange', 'icon' => '๐Ÿš—', 'saran' => [ 'actions' => ['Penataan area parkir', 'Tarif transparan', 'Petugas lebih ramah'], 'dampak' => 'Mengurangi keluhan', 'tip' => 'Sistem parkir lebih rapi dan transparan.', ], ], 'Harga / Tiket' => [ 'keywords' => ['mahal', 'harga', 'tiket', 'bayar', 'biaya', 'tarif', 'murah', 'terjangkau'], 'color' => 'yellow', 'icon' => '๐ŸŽŸ๏ธ', 'saran' => [ 'actions' => ['Evaluasi harga tiket', 'Promo wisata', 'Diskon tertentu'], 'dampak' => 'Daya tarik meningkat', 'tip' => 'Penyesuaian harga tiket agar lebih terjangkau.', ], ], 'Fasilitas' => [ 'keywords' => ['fasilitas', 'gazebo', 'warung', 'kantin', 'kamar ganti', 'musholla', 'wifi', 'bangku', 'kursi'], 'color' => 'green', 'icon' => '๐Ÿ—๏ธ', 'saran' => [ 'actions' => ['Perbaiki fasilitas rusak', 'Tambah fasilitas umum', 'Perawatan berkala'], 'dampak' => 'Kenyamanan pengunjung meningkat', 'tip' => 'Fasilitas lengkap & terawat meningkatkan kepuasan.', ], ], 'Keramaian' => [ 'keywords' => ['ramai', 'macet', 'antri', 'sesak', 'penuh', 'padat', 'berdesakan'], 'color' => 'blue', 'icon' => '๐Ÿ‘ฅ', 'saran' => [ 'actions' => ['Atur kapasitas pengunjung', 'Sistem antrean', 'Jam kunjungan fleksibel'], 'dampak' => 'Pengalaman pengunjung lebih nyaman', 'tip' => 'Manajemen kapasitas pengunjung lebih baik.', ], ], ]; public function index(Request $request) { // --- 1. Dropdown destinasi --- $destinasiList = DB::table('hasil_analisis') ->select('wisata') ->distinct() ->pluck('wisata'); // --- 2. Query dengan filter destinasi --- $queryAll = HasilAnalisis::query(); $queryFilter = HasilAnalisis::query(); if ($request->filled('destinasi')) { $queryFilter->where('wisata', $request->destinasi); } // --- 3. Hitung total & sentimen --- $totalUlasan = $queryFilter->count(); $totalNegatif = (clone $queryFilter)->where('sentimen', 'negatif')->count(); $totalPositif = (clone $queryFilter)->where('sentimen', 'positif')->count(); $totalNetral = (clone $queryFilter)->where('sentimen', 'netral')->count(); $persenNegatif = $totalUlasan > 0 ? round(($totalNegatif / $totalUlasan) * 100, 2) : 0; $tingkatKepuasan = $totalUlasan > 0 ? round(($totalPositif / $totalUlasan) * 100) : 0; // Label kepuasan $labelKepuasan = match(true) { $tingkatKepuasan >= 80 => 'Baik', $tingkatKepuasan >= 60 => 'Sedang', default => 'Kurang', }; // --- 4. Ambil ulasan negatif & bersihkan teks --- $ulasanNegatif = (clone $queryFilter) ->where('sentimen', 'negatif') ->pluck('ulasan_bersih') // gunakan kolom yang sudah dipreproses ->toArray(); $text = strtolower(implode(' ', $ulasanNegatif)); $words = array_filter(preg_split('/\s+/', $text)); // --- 5. Rule-based: hitung skor tiap kategori isu --- $issueSkor = []; $issueWords = []; // kata dominan per kategori foreach ($this->issueRules as $kategori => $rule) { $skor = 0; $matchWords = []; foreach ($rule['keywords'] as $kw) { $count = substr_count($text, $kw); if ($count > 0) { $skor += $count; $matchWords[$kw] = $count; } } $issueSkor[$kategori] = $skor; $issueWords[$kategori] = $matchWords; } // Urutkan berdasarkan skor tertinggi arsort($issueSkor); $totalSkorIsu = array_sum($issueSkor) ?: 1; // hindari division by zero // --- 6. Isu utama (top 5) dengan persentase --- $isuUtama = []; foreach (array_slice($issueSkor, 0, 5, true) as $nama => $skor) { $isuUtama[] = [ 'nama' => $nama, 'skor' => $skor, 'persen' => round(($skor / $totalSkorIsu) * 100), 'color' => $this->issueRules[$nama]['color'], 'icon' => $this->issueRules[$nama]['icon'], ]; } // --- 7. Isu dominan (ranking 1) --- $isuDominan = $isuUtama[0]['nama'] ?? 'Belum ada isu'; $isuDominanPersen = $isuUtama[0]['persen'] ?? 0; // --- 8. Kata kunci dominan (global, top 10, filter stopword) --- $stopwords = [ 'yang', 'dan', 'di', 'ke', 'dari', 'untuk', 'dengan', 'ini', 'itu', 'tidak', 'ada', 'juga', 'sangat', 'lebih', 'sudah', 'bisa', 'tapi', 'karena', 'pada', 'akan', 'atau', 'saya', 'kami', 'mereka', 'nya', 'ga', 'gak', 'udah', 'pas', 'kita', 'sih', 'deh', 'aja', 'ya', 'yg', 'tp', 'bgt', ]; $freq = array_count_values($words); foreach ($stopwords as $sw) { unset($freq[$sw]); } // filter kata pendek (< 3 karakter) foreach (array_keys($freq) as $w) { if (mb_strlen($w) < 3) unset($freq[$w]); } arsort($freq); $kataDominan = array_slice($freq, 0, 10, true); // --- 9. Prioritas rekomendasi (top 3 isu) --- $prioritas = []; $rank = 1; foreach (array_slice($issueSkor, 0, 3, true) as $nama => $skor) { $prioritas[] = [ 'rank' => $rank++, 'nama' => $nama, 'icon' => $this->issueRules[$nama]['icon'], 'actions' => $this->issueRules[$nama]['saran']['actions'], 'dampak' => $this->issueRules[$nama]['saran']['dampak'], 'color' => $this->issueRules[$nama]['color'], ]; } // --- 10. Saran perbaikan (top 3) --- $saranPerbaikan = []; foreach (array_slice($issueSkor, 0, 3, true) as $nama => $skor) { $saranPerbaikan[] = [ 'nama' => 'Perbaikan ' . $nama, 'tip' => $this->issueRules[$nama]['saran']['tip'], 'icon' => $this->issueRules[$nama]['icon'], ]; } // --- 11. Filter destinasi yang sedang aktif --- $destinasiAktif = $request->input('destinasi', 'Semua Destinasi'); return view('rekomendasi.index', compact( 'destinasiList', 'destinasiAktif', 'totalUlasan', 'totalNegatif', 'totalPositif', 'totalNetral', 'persenNegatif', 'tingkatKepuasan', 'labelKepuasan', 'isuUtama', 'isuDominan', 'isuDominanPersen', 'kataDominan', 'saranPerbaikan', 'prioritas', )); } }