Refine recommendation flow and chatbot behavior
This commit is contained in:
parent
c86ed6511e
commit
fcac0ac627
File diff suppressed because one or more lines are too long
|
|
@ -118,6 +118,7 @@ public function send(Request $request)
|
|||
'recommendation' => $recentRecommendation['jurusan'] ?? null,
|
||||
'score' => isset($recentRecommendation['skor']) ? number_format(($recentRecommendation['skor'] > 1 ? $recentRecommendation['skor'] : $recentRecommendation['skor'] * 100), 1) : null,
|
||||
'top3' => $recentRecommendation['top3'] ?? [],
|
||||
'intent' => $this->detectIntent($message),
|
||||
'profile' => [
|
||||
'nama' => $user->name,
|
||||
'kelompok' => $user->kelompok_asal ?? null,
|
||||
|
|
@ -339,4 +340,48 @@ private function stripMarkdown(string $text): string
|
|||
$text = preg_replace('/`(.*?)`/s', '$1', $text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function detectIntent(string $message): string
|
||||
{
|
||||
$message = strtolower($message);
|
||||
|
||||
if (
|
||||
str_contains($message, 'banding') ||
|
||||
str_contains($message, 'beda') ||
|
||||
str_contains($message, 'vs') ||
|
||||
str_contains($message, 'dibanding')
|
||||
) {
|
||||
return 'compare_majors';
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($message, 'jelaskan semua') ||
|
||||
str_contains($message, 'semua jurusan')
|
||||
) {
|
||||
return 'explain_all_majors';
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($message, 'lanjut') ||
|
||||
str_contains($message, 'yang tadi') ||
|
||||
str_contains($message, 'yang sebelumnya') ||
|
||||
str_contains($message, 'maksudnya')
|
||||
) {
|
||||
return 'follow_up';
|
||||
}
|
||||
|
||||
if (str_contains($message, 'kenapa') || str_contains($message, 'mengapa')) {
|
||||
return 'ask_reason';
|
||||
}
|
||||
|
||||
if (
|
||||
str_contains($message, 'prospek') ||
|
||||
str_contains($message, 'karir') ||
|
||||
str_contains($message, 'kerja')
|
||||
) {
|
||||
return 'ask_career';
|
||||
}
|
||||
|
||||
return 'general';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public function index()
|
|||
* Generate textual explanation untuk setiap kriteria
|
||||
* Menjelaskan "mengapa jurusan ini cocok" berdasarkan scoring detail
|
||||
*/
|
||||
private function generateExplanation($jurusanNama, $detail, $katNilai, $kategoriMinat, $prefStudi, $prestasi)
|
||||
private function generateExplanation($jurusanNama, $detail, $katNilai, $kategoriMinat, $prefStudi, $prestasi, array $prestasiAnalysis = [])
|
||||
{
|
||||
$explanations = [];
|
||||
|
||||
|
|
@ -78,12 +78,25 @@ private function generateExplanation($jurusanNama, $detail, $katNilai, $kategori
|
|||
|
||||
// 5. Penjelasan Prestasi
|
||||
$skorPrestasi = $detail['prestasi'] ?? 0;
|
||||
if (!($prestasiAnalysis['provided'] ?? false)) {
|
||||
$explanations['prestasi'] = "ℹ️ Prestasi tidak diisi, sehingga atribut prestasi tidak dihitung pada proses skoring.";
|
||||
return $explanations;
|
||||
}
|
||||
|
||||
$levelPrestasi = $prestasiAnalysis['level'] ?? 'minimal';
|
||||
$labelLevel = [
|
||||
'tinggi' => 'tinggi',
|
||||
'sedang' => 'menengah',
|
||||
'cukup' => 'dasar',
|
||||
'minimal' => 'minimal',
|
||||
][$levelPrestasi] ?? 'minimal';
|
||||
|
||||
if ($skorPrestasi >= 0.7) {
|
||||
$explanations['prestasi'] = "✅ Prestasi Anda mencerminkan potensi kuat untuk sukses dan berkembang di jurusan ini.";
|
||||
$explanations['prestasi'] = "✅ Prestasi Anda terdeteksi pada level {$labelLevel} dan memberi kontribusi kuat untuk kecocokan jurusan ini.";
|
||||
} elseif ($skorPrestasi >= 0.4) {
|
||||
$explanations['prestasi'] = "✓ Prestasi Anda menunjukkan kemampuan dasar yang memadai dan relevan.";
|
||||
$explanations['prestasi'] = "✓ Prestasi Anda berada pada level {$labelLevel} dan tetap dipertimbangkan sebagai faktor pendukung.";
|
||||
} else {
|
||||
$explanations['prestasi'] = "ℹ️ Prestasi tidak menjadi hambatan untuk mengembangkan diri dan berkembang di jurusan ini.";
|
||||
$explanations['prestasi'] = "ℹ️ Input prestasi tetap dihitung (level {$labelLevel}), namun saat ini kontribusinya relatif kecil dibanding faktor utama lain.";
|
||||
}
|
||||
|
||||
return $explanations;
|
||||
|
|
@ -91,6 +104,40 @@ private function generateExplanation($jurusanNama, $detail, $katNilai, $kategori
|
|||
|
||||
public function proses(Request $request)
|
||||
{
|
||||
// Pastikan perhitungan Naive Bayes selalu berbasis 5 atribut input rekomendasi:
|
||||
// 1) Nilai akademik, 2) Minat, 3) Preferensi studi, 4) Cita-cita, 5) Prestasi.
|
||||
$user = Auth::user();
|
||||
$kelompokAsal = strtoupper($user->kelompok_asal ?? 'IPA');
|
||||
|
||||
$rules = [
|
||||
'mtk' => 'nullable|numeric|min:0|max:100',
|
||||
'fisika' => 'nullable|numeric|min:0|max:100',
|
||||
'kimia' => 'nullable|numeric|min:0|max:100',
|
||||
'biologi' => 'nullable|numeric|min:0|max:100',
|
||||
'ekonomi' => 'nullable|numeric|min:0|max:100',
|
||||
'geografi' => 'nullable|numeric|min:0|max:100',
|
||||
'sosiologi' => 'nullable|numeric|min:0|max:100',
|
||||
'sejarah' => 'nullable|numeric|min:0|max:100',
|
||||
'minat' => 'required|string|max:255',
|
||||
'pref_studi' => 'required|string',
|
||||
'cita_cita' => 'required|string|max:255',
|
||||
'prestasi' => 'nullable|string|max:255',
|
||||
];
|
||||
|
||||
if ($kelompokAsal === 'IPA') {
|
||||
$rules['mtk'] = 'required|numeric|min:0|max:100';
|
||||
$rules['fisika'] = 'required|numeric|min:0|max:100';
|
||||
$rules['kimia'] = 'required|numeric|min:0|max:100';
|
||||
$rules['biologi'] = 'required|numeric|min:0|max:100';
|
||||
} else {
|
||||
$rules['ekonomi'] = 'required|numeric|min:0|max:100';
|
||||
$rules['geografi'] = 'required|numeric|min:0|max:100';
|
||||
$rules['sosiologi'] = 'required|numeric|min:0|max:100';
|
||||
$rules['sejarah'] = 'required|numeric|min:0|max:100';
|
||||
}
|
||||
|
||||
$validated = $request->validate($rules);
|
||||
|
||||
// --- 1. PREPROCESSING NILAI (Kriteria 1: Akademik) ---
|
||||
$scores = $request->only(['mtk', 'fisika', 'kimia', 'biologi', 'ekonomi', 'geografi', 'sosiologi', 'sejarah']);
|
||||
$validScores = array_filter($scores);
|
||||
|
|
@ -107,23 +154,29 @@ public function proses(Request $request)
|
|||
}
|
||||
|
||||
// --- 2. ANALISIS MINAT (Kriteria 2) ---
|
||||
$minatRaw = strtolower($request->minat ?? '');
|
||||
$minatInput = trim((string) ($validated['minat'] ?? ''));
|
||||
$minatRaw = strtolower($minatInput);
|
||||
$minatMapped = $this->mapMinat($minatRaw);
|
||||
|
||||
// --- 3. ANALISIS CITA-CITA (Kriteria 3) ---
|
||||
$citaRaw = strtolower($request->cita_cita ?? '');
|
||||
$citaMapped = $this->mapCitaCita($citaRaw);
|
||||
|
||||
// --- 4. PEMETAAN PREFERENSI STUDI (Kriteria 4) ---
|
||||
$prefStudi = $request->pref_studi ?? 'Blended';
|
||||
// --- 3. PREFERENSI STUDI LANJUTAN (Kriteria 3) ---
|
||||
$prefStudi = $validated['pref_studi'];
|
||||
$prefMapping = config('polije.pref_mapping', []);
|
||||
|
||||
// --- 4. ANALISIS CITA-CITA (Kriteria 4) ---
|
||||
$citaInput = trim((string) ($validated['cita_cita'] ?? ''));
|
||||
$citaRaw = strtolower($citaInput);
|
||||
$citaMapped = $this->mapCitaCita($citaRaw);
|
||||
|
||||
// --- 5. ANALISIS PRESTASI (Kriteria 5) ---
|
||||
$prestasiRaw = strtolower($request->prestasi ?? '');
|
||||
$prestasiScore = $this->scorePrestasiScore($prestasiRaw);
|
||||
$prestasiInput = trim((string) ($validated['prestasi'] ?? ''));
|
||||
$isPrestasiFilled = $prestasiInput !== '';
|
||||
$prestasiRaw = strtolower($prestasiInput);
|
||||
$prestasiAnalysis = $this->analyzePrestasi($prestasiRaw);
|
||||
$prestasiScore = $prestasiAnalysis['score'];
|
||||
|
||||
// --- 6. PERHITUNGAN NAIVE BAYES BERBOBOT ---
|
||||
$cfg = config('polije.criteria', []);
|
||||
$majorMap = PolijeMajor::all()->keyBy('nama_jurusan');
|
||||
$logPosteriors = [];
|
||||
$detailPerJurusan = [];
|
||||
$epsilon = 1e-9;
|
||||
|
|
@ -135,16 +188,43 @@ public function proses(Request $request)
|
|||
|
||||
// Weights dan match probabilities
|
||||
$weights = $c['weights'] ?? ['nilai' => 0.40, 'minat' => 0.35, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05];
|
||||
|
||||
// Jika prestasi kosong, atribut prestasi tidak dihitung.
|
||||
if (!$isPrestasiFilled) {
|
||||
$weights['prestasi'] = 0.0;
|
||||
$sumNonPrestasi = ($weights['nilai'] ?? 0) + ($weights['minat'] ?? 0) + ($weights['pref'] ?? 0) + ($weights['cita_cita'] ?? 0);
|
||||
if ($sumNonPrestasi > 0) {
|
||||
$weights['nilai'] = ($weights['nilai'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['minat'] = ($weights['minat'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['pref'] = ($weights['pref'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['cita_cita'] = ($weights['cita_cita'] ?? 0) / $sumNonPrestasi;
|
||||
}
|
||||
}
|
||||
$matchProb = $c['match_prob'] ?? ['nilai' => 0.80, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.65, 'cita_cita' => 0.85];
|
||||
|
||||
// 1. Likelihood untuk Nilai
|
||||
$p_nilai = ($katNilai == ($c['nilai'] ?? 'Sedang')) ? $matchProb['nilai'] : max(1 - $matchProb['nilai'], $epsilon);
|
||||
// Tetap berbasis atribut Nilai Akademik, namun dibuat lebih granular:
|
||||
// kombinasi kategori nilai + kecocokan bobot mapel per jurusan (dari data PolijeMajor).
|
||||
$p_nilai_category = ($katNilai == ($c['nilai'] ?? 'Sedang'))
|
||||
? $matchProb['nilai']
|
||||
: max(1 - $matchProb['nilai'], $epsilon);
|
||||
$p_nilai_subject = $this->scoreSubjectFitLikelihood(
|
||||
$majorMap[$jurusan]->bobot_mapel ?? [],
|
||||
$scores,
|
||||
$p_nilai_category
|
||||
);
|
||||
$p_nilai = max(0.05, min(0.98, (0.6 * $p_nilai_category) + (0.4 * $p_nilai_subject)));
|
||||
|
||||
// 2. Likelihood untuk Minat
|
||||
$p_minat = ($minatMapped == ($c['minat'] ?? 'Umum')) ? $matchProb['minat'] : max(1 - $matchProb['minat'], $epsilon);
|
||||
$p_minat = $this->scoreMinatLikelihood(
|
||||
$minatRaw,
|
||||
$minatMapped,
|
||||
$c['minat'] ?? 'Umum',
|
||||
$matchProb['minat']
|
||||
);
|
||||
|
||||
// 3. Likelihood untuk Preferensi Studi
|
||||
$prefList = $c['pref'] ?? ['Praktik Langsung', 'DuDi', 'Project Based'];
|
||||
$prefList = $c['pref'] ?? ['Sains & Teknologi', 'Pertanian & Lingkungan', 'Kesehatan & Ilmu Hayat', 'Bisnis & Manajemen', 'Sosial & Humaniora'];
|
||||
if (!is_array($prefList)) {
|
||||
$prefList = [$prefList];
|
||||
}
|
||||
|
|
@ -152,19 +232,14 @@ public function proses(Request $request)
|
|||
|
||||
// 4. Likelihood untuk Cita-cita
|
||||
$citaCitaKeywords = $c['cita_cita_keywords'] ?? [];
|
||||
$matchCitaCita = false;
|
||||
if (!empty($citaCitaKeywords)) {
|
||||
foreach ($citaCitaKeywords as $keyword) {
|
||||
if (stripos($citaMapped, $keyword) !== false) {
|
||||
$matchCitaCita = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$p_cita_cita = $matchCitaCita ? $matchProb['cita_cita'] : max(1 - $matchProb['cita_cita'], $epsilon);
|
||||
$p_cita_cita = $this->scoreKeywordLikelihood($citaMapped, $citaCitaKeywords, $matchProb['cita_cita']);
|
||||
|
||||
// 5. Likelihood untuk Prestasi (boost jika ada prestasi)
|
||||
$p_prestasi = ($prestasiScore > 0.5) ? $matchProb['prestasi'] : max(1 - $matchProb['prestasi'], $epsilon);
|
||||
// 5. Likelihood untuk Prestasi (bertingkat: tinggi/menengah/dasar/minimal)
|
||||
$p_prestasi = $this->scorePrestasiLikelihood(
|
||||
$prestasiAnalysis,
|
||||
$citaCitaKeywords,
|
||||
$matchProb['prestasi']
|
||||
);
|
||||
|
||||
// Simpan detail per kriteria untuk tampilan
|
||||
$detailPerJurusan[$jurusan] = [
|
||||
|
|
@ -172,7 +247,7 @@ public function proses(Request $request)
|
|||
'minat' => round($p_minat, 4),
|
||||
'pref' => round($p_pref, 4),
|
||||
'cita' => round($p_cita_cita, 4),
|
||||
'prestasi' => round($p_prestasi, 4),
|
||||
'prestasi' => $isPrestasiFilled ? round($p_prestasi, 4) : null,
|
||||
];
|
||||
|
||||
// Hitung log-likelihood dengan bobot
|
||||
|
|
@ -180,8 +255,11 @@ public function proses(Request $request)
|
|||
($weights['nilai'] ?? 0) * log(max($p_nilai, $epsilon)) +
|
||||
($weights['minat'] ?? 0) * log(max($p_minat, $epsilon)) +
|
||||
($weights['pref'] ?? 0) * log(max($p_pref, $epsilon)) +
|
||||
($weights['cita_cita'] ?? 0) * log(max($p_cita_cita, $epsilon)) +
|
||||
($weights['prestasi'] ?? 0) * log(max($p_prestasi, $epsilon));
|
||||
($weights['cita_cita'] ?? 0) * log(max($p_cita_cita, $epsilon));
|
||||
|
||||
if (($weights['prestasi'] ?? 0) > 0) {
|
||||
$logLikelihood += ($weights['prestasi'] ?? 0) * log(max($p_prestasi, $epsilon));
|
||||
}
|
||||
|
||||
$logPosteriors[$jurusan] = $logPrior + $logLikelihood;
|
||||
}
|
||||
|
|
@ -205,7 +283,8 @@ public function proses(Request $request)
|
|||
$katNilai,
|
||||
$minatMapped,
|
||||
$prefStudi,
|
||||
$prestasiRaw
|
||||
$prestasiRaw,
|
||||
$prestasiAnalysis
|
||||
);
|
||||
$hasilAkhir[] = [
|
||||
'jurusan' => $jurusan,
|
||||
|
|
@ -234,10 +313,11 @@ public function proses(Request $request)
|
|||
'geografi' => $request->geografi ?? null,
|
||||
'sosiologi' => $request->sosiologi ?? null,
|
||||
'sejarah' => $request->sejarah ?? null,
|
||||
'minat' => $request->minat ?? null,
|
||||
'preferensi_studi' => $request->pref_studi ?? null,
|
||||
'cita_cita' => $request->cita_cita ?? null,
|
||||
'prestasi' => $request->prestasi ?? null,
|
||||
'minat' => $minatInput,
|
||||
'preferensi_studi' => $prefStudi,
|
||||
'cita_cita' => $citaInput,
|
||||
// Kolom prestasi di DB bersifat NOT NULL, jadi simpan string kosong jika tidak diisi.
|
||||
'prestasi' => $prestasiInput,
|
||||
'hasil_rekomendasi' => $hasilAkhir,
|
||||
]);
|
||||
}
|
||||
|
|
@ -256,7 +336,13 @@ public function proses(Request $request)
|
|||
]);
|
||||
}
|
||||
|
||||
return view('rekomendasi.hasil', compact('hasilAkhir', 'katNilai', 'minatMapped', 'citaMapped', 'prefStudi', 'prestasiScore'));
|
||||
// Ambil data jurusan teratas dari database untuk deskripsi/prospek pada halaman hasil
|
||||
$topJurusan = null;
|
||||
if (count($hasilAkhir) > 0) {
|
||||
$topJurusan = PolijeMajor::where('nama_jurusan', $hasilAkhir[0]['jurusan'] ?? '')->first();
|
||||
}
|
||||
|
||||
return view('rekomendasi.hasil', compact('hasilAkhir', 'katNilai', 'average', 'minatMapped', 'citaMapped', 'prefStudi', 'prestasiScore', 'topJurusan', 'isPrestasiFilled'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -313,6 +399,153 @@ private function scorePrestasiScore(string $prestasiRaw): float
|
|||
return $prestasiScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ringkas level prestasi dari input teks agar lebih transparan.
|
||||
*/
|
||||
private function analyzePrestasi(string $prestasiRaw): array
|
||||
{
|
||||
if (empty(trim($prestasiRaw))) {
|
||||
return [
|
||||
'provided' => false,
|
||||
'level' => 'minimal',
|
||||
'score' => 0.0,
|
||||
'raw' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$text = strtolower(trim($prestasiRaw));
|
||||
$level = 'minimal';
|
||||
|
||||
if (preg_match('/(juara|menang|champion|first|gold|emas|terbaik)/', $text)) {
|
||||
$level = 'tinggi';
|
||||
} elseif (preg_match('/(finalis|semifinal|peringkat|ranking|podium|medali|silver|perak)/', $text)) {
|
||||
$level = 'sedang';
|
||||
} elseif (preg_match('/(sertifikat|training|kursus|workshop|peserta|mengikuti)/', $text)) {
|
||||
$level = 'cukup';
|
||||
}
|
||||
|
||||
return [
|
||||
'provided' => true,
|
||||
'level' => $level,
|
||||
'score' => $this->scorePrestasiScore($text),
|
||||
'raw' => $text,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Skor atribut teks berdasarkan coverage keyword (0..1) lalu dipetakan menjadi likelihood.
|
||||
*/
|
||||
private function scoreKeywordLikelihood(string $text, array $keywords, float $matchProb): float
|
||||
{
|
||||
if (empty($keywords)) {
|
||||
return 0.50;
|
||||
}
|
||||
|
||||
$coverage = $this->keywordCoverage($text, $keywords);
|
||||
|
||||
// Base 0.2 agar tidak 0 total, lalu naik proporsional coverage.
|
||||
$likelihood = 0.20 + ($coverage * ($matchProb - 0.20));
|
||||
|
||||
return max(0.05, min(0.98, $likelihood));
|
||||
}
|
||||
|
||||
private function scoreMinatLikelihood(string $minatRaw, string $minatMapped, string $targetMinat, float $matchProb): float
|
||||
{
|
||||
$keywordBank = [
|
||||
'Logika & Komputer' => ['coding', 'programming', 'komputer', 'software', 'web', 'data', 'ai', 'digital'],
|
||||
'Alam & Tanaman' => ['pertanian', 'tanaman', 'kebun', 'sawah', 'alam', 'peternakan', 'agribisnis'],
|
||||
'Pelayanan & Kesehatan' => ['kesehatan', 'medis', 'gizi', 'perawat', 'dokter', 'klinik', 'rumah sakit'],
|
||||
'Manajemen & Bisnis' => ['bisnis', 'usaha', 'marketing', 'keuangan', 'manajemen', 'akuntansi', 'entrepreneur'],
|
||||
'Mesin & Listrik' => ['mesin', 'listrik', 'teknik', 'otomasi', 'elektronik', 'mekanik', 'industri'],
|
||||
];
|
||||
|
||||
$targetKeywords = $keywordBank[$targetMinat] ?? [];
|
||||
$coverage = $this->keywordCoverage($minatRaw, $targetKeywords);
|
||||
$categoryMatch = ($minatMapped === $targetMinat) ? 1.0 : 0.0;
|
||||
|
||||
// Kombinasi semantic match + category match.
|
||||
$combined = (0.6 * $coverage) + (0.4 * $categoryMatch);
|
||||
$likelihood = 0.20 + ($combined * ($matchProb - 0.20));
|
||||
|
||||
return max(0.05, min(0.98, $likelihood));
|
||||
}
|
||||
|
||||
private function scorePrestasiLikelihood(array $prestasiAnalysis, array $jurusanKeywords, float $matchProb): float
|
||||
{
|
||||
$baseScore = $prestasiAnalysis['score'] ?? 0.0; // 0..1
|
||||
|
||||
if ($baseScore <= 0.0) {
|
||||
return 0.20;
|
||||
}
|
||||
|
||||
// Relevansi prestasi terhadap konteks jurusan (dari teks prestasi vs keyword jurusan)
|
||||
$relevance = 0.0;
|
||||
if (!empty($jurusanKeywords)) {
|
||||
$relevance = $this->keywordCoverage($prestasiAnalysis['level'] . ' ' . ($prestasiAnalysis['raw'] ?? ''), $jurusanKeywords);
|
||||
}
|
||||
|
||||
// Prestasi level dominan, relevance sebagai penguat.
|
||||
$combined = (0.75 * $baseScore) + (0.25 * $relevance);
|
||||
$likelihood = 0.20 + ($combined * ($matchProb - 0.20));
|
||||
|
||||
return max(0.05, min(0.98, $likelihood));
|
||||
}
|
||||
|
||||
private function keywordCoverage(string $text, array $keywords): float
|
||||
{
|
||||
$text = strtolower(trim($text));
|
||||
if ($text === '' || empty($keywords)) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$matched = 0;
|
||||
foreach (array_unique($keywords) as $keyword) {
|
||||
if ($keyword !== '' && str_contains($text, strtolower($keyword))) {
|
||||
$matched++;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalisasi agar tidak terlalu menghukum list keyword yang panjang.
|
||||
$denominator = max(1, min(count(array_unique($keywords)), 6));
|
||||
|
||||
return min(1.0, $matched / $denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hitung kecocokan nilai mapel terhadap bobot mapel jurusan (0..1) lalu ubah ke likelihood.
|
||||
* Ini tetap bagian dari atribut "Nilai Akademik" agar tidak keluar dari 5 atribut.
|
||||
*/
|
||||
private function scoreSubjectFitLikelihood(array $bobotMapel, array $scores, float $fallback): float
|
||||
{
|
||||
if (empty($bobotMapel)) {
|
||||
return max(0.05, min(0.98, $fallback));
|
||||
}
|
||||
|
||||
$weighted = 0.0;
|
||||
$weightSum = 0.0;
|
||||
|
||||
foreach ($bobotMapel as $mapel => $w) {
|
||||
$nilai = $scores[$mapel] ?? null;
|
||||
if ($nilai === null || $nilai === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$num = (float) $nilai;
|
||||
$normalized = max(0.0, min(1.0, $num / 100));
|
||||
$weighted += $normalized * (float) $w;
|
||||
$weightSum += (float) $w;
|
||||
}
|
||||
|
||||
if ($weightSum <= 0) {
|
||||
return max(0.05, min(0.98, $fallback));
|
||||
}
|
||||
|
||||
$fitScore = $weighted / $weightSum; // 0..1
|
||||
|
||||
// Map ke likelihood agar tidak terlalu ekstrem.
|
||||
return max(0.05, min(0.98, 0.25 + (0.70 * $fitScore)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tampilkan history rekomendasi
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -33,6 +33,17 @@ public function chat($message, $context = [], $chatHistory = [])
|
|||
];
|
||||
}
|
||||
|
||||
// Intent router: mode perbandingan jurusan ditangani terstruktur agar konsisten.
|
||||
if (($context['intent'] ?? '') === 'compare_majors') {
|
||||
$comparison = $this->buildStructuredComparisonResponse($message, $context);
|
||||
if (!empty($comparison)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => $comparison,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$systemPrompt = $this->buildSystemPrompt($context);
|
||||
|
||||
// Build multi-turn conversation for Gemini
|
||||
|
|
@ -102,7 +113,7 @@ public function chat($message, $context = [], $chatHistory = [])
|
|||
|
||||
// All models failed
|
||||
Log::error('All Gemini models failed, using fallback');
|
||||
return $this->getFallbackResponse($message, $context);
|
||||
return $this->getFallbackResponse($message, $context, $chatHistory);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Gemini Service Exception', [
|
||||
|
|
@ -111,18 +122,68 @@ public function chat($message, $context = [], $chatHistory = [])
|
|||
'line' => $e->getLine()
|
||||
]);
|
||||
|
||||
return $this->getFallbackResponse($message, $context);
|
||||
return $this->getFallbackResponse($message, $context, $chatHistory);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFallbackResponse($message, $context = [])
|
||||
protected function getFallbackResponse($message, $context = [], $chatHistory = [])
|
||||
{
|
||||
$jurusan = $context['recommendation'] ?? null;
|
||||
$score = isset($context['score']) ? floatval($context['score']) : 0;
|
||||
$hasRecommendation = !empty($jurusan);
|
||||
|
||||
if (($context['intent'] ?? '') === 'compare_majors') {
|
||||
$comparison = $this->buildStructuredComparisonResponse($message, $context);
|
||||
if (!empty($comparison)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => $comparison,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$major = null;
|
||||
if ($hasRecommendation) {
|
||||
$major = PolijeMajor::where('nama_jurusan', $jurusan)->first();
|
||||
}
|
||||
$majorDesc = $major->deskripsi ?? null;
|
||||
$majorProspek = $major->prospek_kerja ?? null;
|
||||
|
||||
// Keyword-based responses
|
||||
$messageLower = strtolower($message);
|
||||
$lastAiMessage = $this->getLastAssistantMessage($chatHistory);
|
||||
|
||||
// Tangani pertanyaan lanjutan agar tetap nyambung saat fallback aktif
|
||||
if ($this->isFollowUpMessage($messageLower)) {
|
||||
if (
|
||||
strpos($messageLower, 'jelaskan semua') !== false ||
|
||||
strpos($messageLower, 'semua jurusan') !== false ||
|
||||
strpos($messageLower, 'satu satu') !== false ||
|
||||
strpos($messageLower, 'satu-satu') !== false
|
||||
) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => $this->buildAllMajorsResponse($hasRecommendation, $jurusan, $score),
|
||||
];
|
||||
}
|
||||
|
||||
if ($hasRecommendation) {
|
||||
$parts = [];
|
||||
$parts[] = "Menindaklanjuti pembahasan sebelumnya, fokus utama Anda saat ini tetap pada jurusan \"{$jurusan}\" dengan skor kesesuaian {$score}%.";
|
||||
if (!empty($majorDesc)) {
|
||||
$parts[] = "Fokus pembelajaran jurusan: {$majorDesc}";
|
||||
}
|
||||
if (!empty($majorProspek)) {
|
||||
$parts[] = "Prospek kerja yang relevan: {$majorProspek}";
|
||||
}
|
||||
$parts[] = "Jika Anda berkenan, saya dapat lanjutkan secara bertahap: (1) kompetensi yang harus dipersiapkan, (2) mata kuliah inti, dan (3) perbandingan dengan alternatif jurusan lain.";
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => implode(' ', $parts),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($messageLower, 'halo') !== false || strpos($messageLower, 'hai') !== false || strpos($messageLower, 'hallo') !== false || strpos($messageLower, 'hi') !== false) {
|
||||
$hour = (int) now()->format('H');
|
||||
|
|
@ -148,7 +209,7 @@ protected function getFallbackResponse($message, $context = [])
|
|||
if ($hasRecommendation) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Jurusan \"{$jurusan}\" direkomendasikan berdasarkan analisis komprehensif terhadap profil akademik, minat, serta preferensi studi Anda. Skor kesesuaian sebesar {$score}% menunjukkan tingkat kecocokan yang signifikan antara profil Anda dengan karakteristik jurusan tersebut. Sistem menghitung skor ini berdasarkan lima faktor utama, yaitu: nilai akademik, minat dan bakat, preferensi studi lanjutan, prestasi, dan cita-cita."
|
||||
'message' => "Jurusan \"{$jurusan}\" direkomendasikan karena paling sesuai dengan kombinasi profil Anda. Skor kesesuaian {$score}% diperoleh dari analisis lima atribut: nilai akademik, minat, preferensi studi lanjutan, cita-cita, dan prestasi (jika diisi). Berdasarkan data tersebut, jurusan ini memiliki kecocokan paling kuat dibanding alternatif lain pada sesi analisis Anda."
|
||||
];
|
||||
}
|
||||
return [
|
||||
|
|
@ -157,11 +218,40 @@ protected function getFallbackResponse($message, $context = [])
|
|||
];
|
||||
}
|
||||
|
||||
if (
|
||||
strpos($messageLower, 'apa itu') !== false ||
|
||||
strpos($messageLower, 'jurusan tersebut') !== false ||
|
||||
strpos($messageLower, 'jelaskan jurusan') !== false ||
|
||||
strpos($messageLower, 'maksud jurusan') !== false
|
||||
) {
|
||||
if ($hasRecommendation) {
|
||||
$parts = [];
|
||||
$parts[] = "Jurusan \"{$jurusan}\" adalah bidang yang berfokus pada kompetensi terapan sesuai kebutuhan dunia kerja.";
|
||||
if (!empty($majorDesc)) {
|
||||
$parts[] = "Gambaran jurusan: {$majorDesc}";
|
||||
}
|
||||
if (!empty($majorProspek)) {
|
||||
$parts[] = "Prospek kerja utama: {$majorProspek}";
|
||||
}
|
||||
$parts[] = "Jika Anda berkenan, saya dapat lanjutkan dengan mata kuliah inti, kemampuan yang perlu dipersiapkan, dan alasan kesesuaiannya dengan profil Anda.";
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => implode(' ', $parts),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Saya dapat menjelaskan jurusan secara rinci. Agar lebih tepat sasaran, sebutkan nama jurusan yang ingin Anda ketahui, atau jalankan Analisis Rekomendasi terlebih dahulu agar saya menjelaskan jurusan yang paling sesuai dengan profil Anda.",
|
||||
];
|
||||
}
|
||||
|
||||
if (strpos($messageLower, 'prospek') !== false || strpos($messageLower, 'karir') !== false || strpos($messageLower, 'kerja') !== false) {
|
||||
if ($hasRecommendation) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Jurusan \"{$jurusan}\" memiliki prospek karier yang menjanjikan. Lulusan dari jurusan ini dapat bekerja di berbagai sektor industri yang relevan dengan bidang keahliannya. Setiap jurusan di POLIJE dirancang untuk membekali lulusannya dengan kompetensi praktis yang dibutuhkan oleh dunia kerja. Apakah Anda ingin mengetahui lebih detail mengenai posisi pekerjaan spesifik yang dapat ditempuh?"
|
||||
'message' => "Jurusan \"{$jurusan}\" memiliki prospek karier yang baik. " . (!empty($majorProspek) ? "Contoh prospek kerja: {$majorProspek}. " : "Lulusan dapat bekerja pada bidang yang relevan dengan kompetensi jurusan. ") . "Jika Anda berkenan, saya dapat jelaskan jalur karier dari level awal sampai pengembangan jangka panjang."
|
||||
];
|
||||
}
|
||||
return [
|
||||
|
|
@ -197,11 +287,15 @@ protected function getFallbackResponse($message, $context = [])
|
|||
];
|
||||
}
|
||||
|
||||
// Default response
|
||||
// Default response: tetap menanggapi isi pertanyaan agar nyambung
|
||||
if ($hasRecommendation) {
|
||||
$lead = !empty($lastAiMessage)
|
||||
? "Menindaklanjuti percakapan sebelumnya, "
|
||||
: "";
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Saya adalah konselor BK virtual SMA Bima Ambulu. Berdasarkan hasil analisis, jurusan \"{$jurusan}\" memiliki kesesuaian tertinggi dengan profil Anda, yaitu sebesar {$score}%. Anda dapat berkonsultasi mengenai prospek karier, kompetensi yang dibutuhkan, perbandingan antar jurusan, atau hal lain terkait persiapan pendidikan tinggi. Silakan sampaikan pertanyaan Anda."
|
||||
'message' => $lead . "berdasarkan hasil analisis Anda saat ini, jurusan dengan kecocokan tertinggi adalah \"{$jurusan}\" ({$score}%). " . (!empty($majorDesc) ? "Ringkasan jurusan: {$majorDesc}. " : "") . "Silakan lanjutkan dengan pertanyaan yang lebih spesifik, misalnya perbandingan dengan jurusan lain, kompetensi yang harus dipersiapkan, atau prospek kariernya."
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -319,6 +413,7 @@ protected function buildSystemPrompt($context)
|
|||
}
|
||||
|
||||
$prompt .= "\n\nCara kamu merespons:";
|
||||
$prompt .= "\n0. WAJIB jawab inti pertanyaan pengguna terlebih dahulu secara langsung dalam 1-2 kalimat pertama. Jangan memutar atau memberi jawaban generik yang tidak menanggapi pertanyaan.";
|
||||
$prompt .= "\n1. INGAT seluruh percakapan sebelumnya. Jangan tanya ulang hal yang sudah dijawab siswa.";
|
||||
$prompt .= "\n2. Kalau siswa sudah bilang minat/kemampuan/kesukaan, LANGSUNG analisis dan arahkan ke jurusan yang cocok dengan ALASAN LOGIS (misal: 'kamu suka logika → TI cocok karena...')";
|
||||
$prompt .= "\n3. Berikan REKOMENDASI TEGAS, bukan cuma daftar pilihan. Contoh: 'Menurut Bapak, kamu paling cocok ke Teknologi Informasi. Alasannya: ...'";
|
||||
|
|
@ -327,6 +422,8 @@ protected function buildSystemPrompt($context)
|
|||
$prompt .= "\n6. Jawab RINGKAS (2-3 paragraf). Jangan terlalu panjang kecuali diminta detail.";
|
||||
$prompt .= "\n7. Boleh menjawab pertanyaan di luar topik jurusan secara singkat, lalu kembalikan ke konseling.";
|
||||
$prompt .= "\n8. JANGAN awali setiap respons dengan 'Halo' atau salam — langsung ke inti jawaban (kecuali percakapan baru dimulai).";
|
||||
$prompt .= "\n8a. Jika pengguna bertanya 'apa itu jurusan X' atau 'jelaskan jurusan tersebut', jelaskan definisi jurusan, fokus pembelajaran, dan prospek kerjanya secara ringkas dan nyambung dengan konteks pengguna.";
|
||||
$prompt .= "\n8b. Jika pengguna menilai jawaban tidak nyambung, lakukan klarifikasi singkat lalu jawab ulang secara spesifik sesuai pertanyaan terbaru.";
|
||||
|
||||
// Tambahkan referensi Q&A serupa dari riwayat
|
||||
if (!empty($context['similar_qa'])) {
|
||||
|
|
@ -339,7 +436,232 @@ protected function buildSystemPrompt($context)
|
|||
$prompt .= "\nGunakan referensi di atas untuk menjaga konsistensi jawaban, namun tetap sesuaikan dengan profil dan konteks percakapan siswa saat ini.";
|
||||
} $prompt .= "\n9. DILARANG KERAS menggunakan format markdown seperti **, *, #, ##, atau simbol formatting lainnya. Tulis teks biasa (plain text) saja tanpa formatting markdown.";
|
||||
$prompt .= "\n10. Gunakan bahasa Indonesia baku dan akademik. Hindari bahasa gaul seperti 'kek', 'banget', 'ngobrol', 'ngomongin', 'gampangnya'. Gunakan padanan formal seperti 'sangat', 'berbincang', 'membahas', 'secara sederhana'.";
|
||||
$prompt .= "\n11. Jika pertanyaan bersifat umum di luar jurusan (misalnya pengetahuan umum), jawab singkat namun benar, lalu tawarkan kaitan dengan rencana studi/karier pengguna.";
|
||||
|
||||
if (($context['intent'] ?? '') === 'compare_majors') {
|
||||
$prompt .= "\n12. Pengguna sedang meminta PERBANDINGAN JURUSAN. Gunakan format terstruktur dengan urutan tetap: (1) Fokus pembelajaran, (2) Kompetensi yang perlu dipersiapkan, (3) Prospek kerja, (4) Tantangan belajar, (5) Rekomendasi paling sesuai untuk profil pengguna beserta alasan.";
|
||||
}
|
||||
|
||||
return $prompt;
|
||||
}
|
||||
|
||||
protected function isFollowUpMessage(string $messageLower): bool
|
||||
{
|
||||
$followUpHints = [
|
||||
'jelaskan semua',
|
||||
'lanjut',
|
||||
'lanjutkan',
|
||||
'yang tadi',
|
||||
'yang sebelumnya',
|
||||
'maksudnya',
|
||||
'lebih detail',
|
||||
'perjelas',
|
||||
'itu gimana',
|
||||
'jurusan itu',
|
||||
'jurusan tersebut',
|
||||
'semua jurusan',
|
||||
'satu satu',
|
||||
'satu-satu',
|
||||
];
|
||||
|
||||
foreach ($followUpHints as $hint) {
|
||||
if (strpos($messageLower, $hint) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getLastAssistantMessage(array $chatHistory): ?string
|
||||
{
|
||||
for ($i = count($chatHistory) - 1; $i >= 0; $i--) {
|
||||
$item = $chatHistory[$i] ?? null;
|
||||
if (!$item || !isset($item['role'], $item['text'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($item['role'] === 'ai' && trim((string) $item['text']) !== '') {
|
||||
return (string) $item['text'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function buildAllMajorsResponse(bool $hasRecommendation, ?string $jurusan, float $score): string
|
||||
{
|
||||
$majors = PolijeMajor::orderBy('nama_jurusan')->get();
|
||||
|
||||
if ($majors->isEmpty()) {
|
||||
if ($hasRecommendation) {
|
||||
return "Menindaklanjuti pertanyaan Anda, saat ini rekomendasi utama Anda tetap pada jurusan \"{$jurusan}\" dengan skor {$score}%. Jika Anda berkenan, saya dapat jelaskan detail jurusan ini terlebih dahulu.";
|
||||
}
|
||||
|
||||
return "Data jurusan saat ini belum tersedia. Silakan coba kembali beberapa saat lagi, atau ajukan satu jurusan yang ingin dibahas agar saya jelaskan secara umum.";
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
$lines[] = "Berikut ringkasan seluruh jurusan di Politeknik Negeri Jember agar pembahasan kita tetap nyambung dengan pertanyaan Anda:";
|
||||
|
||||
foreach ($majors as $index => $m) {
|
||||
$desc = trim((string) ($m->deskripsi ?? ''));
|
||||
if ($desc === '') {
|
||||
$desc = 'Berorientasi pada kompetensi terapan yang relevan dengan kebutuhan dunia kerja.';
|
||||
}
|
||||
$num = $index + 1;
|
||||
$lines[] = "{$num}. {$m->nama_jurusan}: {$desc}";
|
||||
}
|
||||
|
||||
if ($hasRecommendation) {
|
||||
$lines[] = "Berdasarkan profil Anda, jurusan yang paling direkomendasikan tetap \"{$jurusan}\" ({$score}%). Jika Anda ingin, saya lanjutkan dengan perbandingan jurusan rekomendasi Anda terhadap 2 alternatif teratas.";
|
||||
} else {
|
||||
$lines[] = "Jika Anda berkenan, saya dapat bantu menyaring 2-3 jurusan paling relevan berdasarkan minat dan nilai Anda.";
|
||||
}
|
||||
|
||||
return implode(' ', $lines);
|
||||
}
|
||||
|
||||
protected function buildStructuredComparisonResponse(string $message, array $context = []): ?string
|
||||
{
|
||||
$majors = PolijeMajor::orderBy('nama_jurusan')->get();
|
||||
if ($majors->count() < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$selected = $this->resolveMajorsForComparison($message, $context, $majors);
|
||||
if (count($selected) < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$a = $selected[0];
|
||||
$b = $selected[1];
|
||||
|
||||
$aDesc = trim((string) ($a->deskripsi ?? ''));
|
||||
$bDesc = trim((string) ($b->deskripsi ?? ''));
|
||||
$aProspek = trim((string) ($a->prospek_kerja ?? ''));
|
||||
$bProspek = trim((string) ($b->prospek_kerja ?? ''));
|
||||
|
||||
if ($aDesc === '') {
|
||||
$aDesc = 'Berfokus pada kompetensi terapan sesuai kebutuhan industri.';
|
||||
}
|
||||
if ($bDesc === '') {
|
||||
$bDesc = 'Berfokus pada kompetensi terapan sesuai kebutuhan industri.';
|
||||
}
|
||||
if ($aProspek === '') {
|
||||
$aProspek = 'Lulusan berpeluang masuk pada bidang kerja yang relevan dengan kompetensi jurusan.';
|
||||
}
|
||||
if ($bProspek === '') {
|
||||
$bProspek = 'Lulusan berpeluang masuk pada bidang kerja yang relevan dengan kompetensi jurusan.';
|
||||
}
|
||||
|
||||
$recommended = $context['recommendation'] ?? null;
|
||||
$winner = $a->nama_jurusan;
|
||||
if (!empty($recommended)) {
|
||||
if (strcasecmp($recommended, $b->nama_jurusan) === 0) {
|
||||
$winner = $b->nama_jurusan;
|
||||
} elseif (strcasecmp($recommended, $a->nama_jurusan) !== 0) {
|
||||
$winner = $a->nama_jurusan;
|
||||
}
|
||||
}
|
||||
|
||||
$score = isset($context['score']) ? (float) $context['score'] : null;
|
||||
$scoreText = $score !== null && $score > 0 ? " dengan skor kesesuaian {$score}%" : "";
|
||||
|
||||
$lines = [];
|
||||
$lines[] = "Perbandingan terstruktur antara Jurusan {$a->nama_jurusan} dan Jurusan {$b->nama_jurusan}:";
|
||||
$lines[] = "1. Fokus pembelajaran";
|
||||
$lines[] = "- {$a->nama_jurusan}: {$aDesc}";
|
||||
$lines[] = "- {$b->nama_jurusan}: {$bDesc}";
|
||||
$lines[] = "2. Kompetensi yang perlu dipersiapkan";
|
||||
$lines[] = "- {$a->nama_jurusan}: Penguasaan konsep inti jurusan, kemampuan analitis, komunikasi profesional, dan disiplin praktik.";
|
||||
$lines[] = "- {$b->nama_jurusan}: Penguasaan konsep inti jurusan, kemampuan analitis, komunikasi profesional, dan disiplin praktik.";
|
||||
$lines[] = "3. Prospek kerja";
|
||||
$lines[] = "- {$a->nama_jurusan}: {$aProspek}";
|
||||
$lines[] = "- {$b->nama_jurusan}: {$bProspek}";
|
||||
$lines[] = "4. Tantangan belajar";
|
||||
$lines[] = "- {$a->nama_jurusan}: Menuntut konsistensi belajar, adaptasi pada praktik lapangan, dan ketekunan menyelesaikan tugas proyek.";
|
||||
$lines[] = "- {$b->nama_jurusan}: Menuntut konsistensi belajar, adaptasi pada praktik lapangan, dan ketekunan menyelesaikan tugas proyek.";
|
||||
$lines[] = "5. Rekomendasi untuk profil Anda";
|
||||
$lines[] = "- Berdasarkan konteks analisis Anda, jurusan yang lebih diprioritaskan adalah {$winner}{$scoreText}. Jika Anda berkenan, saya dapat lanjutkan dengan langkah persiapan 6 bulan pertama agar transisi belajar Anda lebih terarah.";
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
protected function resolveMajorsForComparison(string $message, array $context, $majors): array
|
||||
{
|
||||
$messageLower = mb_strtolower($message);
|
||||
$mentioned = [];
|
||||
|
||||
foreach ($majors as $major) {
|
||||
$name = mb_strtolower((string) $major->nama_jurusan);
|
||||
if ($name !== '' && str_contains($messageLower, $name)) {
|
||||
$mentioned[$major->nama_jurusan] = $major;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($mentioned) >= 2) {
|
||||
return array_slice(array_values($mentioned), 0, 2);
|
||||
}
|
||||
|
||||
$picked = array_values($mentioned);
|
||||
$recommendationName = $context['recommendation'] ?? null;
|
||||
|
||||
if (!empty($recommendationName)) {
|
||||
$recMajor = $majors->first(function ($m) use ($recommendationName) {
|
||||
return strcasecmp((string) $m->nama_jurusan, (string) $recommendationName) === 0;
|
||||
});
|
||||
|
||||
if ($recMajor && !$this->containsMajor($picked, $recMajor->nama_jurusan)) {
|
||||
$picked[] = $recMajor;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($context['top3']) && is_array($context['top3'])) {
|
||||
foreach ($context['top3'] as $candidate) {
|
||||
$name = $candidate['jurusan'] ?? null;
|
||||
if (empty($name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$candidateMajor = $majors->first(function ($m) use ($name) {
|
||||
return strcasecmp((string) $m->nama_jurusan, (string) $name) === 0;
|
||||
});
|
||||
|
||||
if ($candidateMajor && !$this->containsMajor($picked, $candidateMajor->nama_jurusan)) {
|
||||
$picked[] = $candidateMajor;
|
||||
}
|
||||
|
||||
if (count($picked) >= 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($picked) < 2) {
|
||||
foreach ($majors as $major) {
|
||||
if (!$this->containsMajor($picked, $major->nama_jurusan)) {
|
||||
$picked[] = $major;
|
||||
}
|
||||
|
||||
if (count($picked) >= 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_slice($picked, 0, 2);
|
||||
}
|
||||
|
||||
protected function containsMajor(array $picked, string $name): bool
|
||||
{
|
||||
foreach ($picked as $item) {
|
||||
if (strcasecmp((string) $item->nama_jurusan, $name) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@
|
|||
// Standar kriteria per jurusan dengan bobot dan probabilitas kecocokan
|
||||
// Dioptimalkan untuk Polije (Vocational Campus)
|
||||
// Weights: nilai, minat, pref, prestasi, cita_cita
|
||||
// Preference: Praktik Langsung, DuDi, Project Based, Blended
|
||||
// Preference diselaraskan dengan input form rekomendasi:
|
||||
// Sains & Teknologi, Pertanian & Lingkungan, Kesehatan & Ilmu Hayat,
|
||||
// Bisnis & Manajemen, Sosial & Humaniora
|
||||
|
||||
'criteria' => [
|
||||
'Produksi Pertanian' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Praktik Langsung', 'DuDi', 'Project Based'],
|
||||
'cita_cita_keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman'],
|
||||
'pref' => ['Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman', 'agronomi', 'perkebunan', 'hortikultura'],
|
||||
'skills_required' => ['Observasi', 'Kerja Lapangan', 'Pemeliharaan Tanaman'],
|
||||
'weights' => ['nilai' => 0.40, 'minat' => 0.35, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.80, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.65, 'cita_cita' => 0.85],
|
||||
|
|
@ -19,8 +21,8 @@
|
|||
'Teknologi Pertanian' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Praktik Langsung', 'Project Based', 'DuDi'],
|
||||
'cita_cita_keywords' => ['teknologi', 'inovasi', 'otomasi', 'mesin pertanian'],
|
||||
'pref' => ['Sains & Teknologi', 'Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['teknologi', 'inovasi', 'otomasi', 'mesin pertanian', 'smart farming', 'teknologi pangan'],
|
||||
'skills_required' => ['Problem Solving', 'Teknologi', 'Inovasi'],
|
||||
'weights' => ['nilai' => 0.50, 'minat' => 0.25, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.85, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.75, 'cita_cita' => 0.80],
|
||||
|
|
@ -28,8 +30,8 @@
|
|||
'Peternakan' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Praktik Langsung', 'DuDi', 'Project Based'],
|
||||
'cita_cita_keywords' => ['ternak', 'hewan', 'peternakan', 'peeternak', 'sapi', 'ayam', 'unggas'],
|
||||
'pref' => ['Pertanian & Lingkungan', 'Kesehatan & Ilmu Hayat'],
|
||||
'cita_cita_keywords' => ['ternak', 'hewan', 'peternakan', 'peternak', 'sapi', 'ayam', 'unggas', 'veteriner', 'farm'],
|
||||
'skills_required' => ['Perawatan Hewan', 'Kesabaran', 'Manajemen'],
|
||||
'weights' => ['nilai' => 0.40, 'minat' => 0.40, 'pref' => 0.10, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.80, 'minat' => 0.88, 'pref' => 0.80, 'prestasi' => 0.65, 'cita_cita' => 0.88],
|
||||
|
|
@ -37,8 +39,8 @@
|
|||
'Manajemen Agribisnis' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Manajemen & Bisnis',
|
||||
'pref' => ['Project Based', 'DuDi', 'Blended'],
|
||||
'cita_cita_keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha'],
|
||||
'pref' => ['Bisnis & Manajemen', 'Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha', 'manajer', 'marketing', 'wirausaha'],
|
||||
'skills_required' => ['Manajemen', 'Bisnis Acumen', 'Komunikasi'],
|
||||
'weights' => ['nilai' => 0.35, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.75, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
|
|
@ -46,8 +48,8 @@
|
|||
'Teknologi Informasi' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Logika & Komputer',
|
||||
'pref' => ['Praktik Langsung', 'Project Based', 'DuDi'],
|
||||
'cita_cita_keywords' => ['programmer', 'developer', 'coding', 'software', 'web developer', 'hacker', 'it'],
|
||||
'pref' => ['Sains & Teknologi'],
|
||||
'cita_cita_keywords' => ['programmer', 'developer', 'coding', 'software', 'web developer', 'hacker', 'it', 'data analyst', 'ai engineer', 'mobile developer'],
|
||||
'skills_required' => ['Coding', 'Problem Solving', 'Logika'],
|
||||
'weights' => ['nilai' => 0.45, 'minat' => 0.35, 'pref' => 0.12, 'prestasi' => 0.05, 'cita_cita' => 0.03],
|
||||
'match_prob' => ['nilai' => 0.90, 'minat' => 0.92, 'pref' => 0.85, 'prestasi' => 0.75, 'cita_cita' => 0.85],
|
||||
|
|
@ -55,8 +57,8 @@
|
|||
'Teknik' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Mesin & Listrik',
|
||||
'pref' => ['Praktik Langsung', 'DuDi', 'Project Based'],
|
||||
'cita_cita_keywords' => ['mesin', 'bengkel', 'teknisi', 'listrik', 'elektronik', 'automasi', 'instalasi', 'panel'],
|
||||
'pref' => ['Sains & Teknologi'],
|
||||
'cita_cita_keywords' => ['mesin', 'bengkel', 'teknisi', 'listrik', 'elektronik', 'otomasi', 'instalasi', 'panel', 'mekatronika', 'maintenance'],
|
||||
'skills_required' => ['Mekanik', 'Elektrik', 'Teknik', 'Presisi'],
|
||||
'weights' => ['nilai' => 0.42, 'minat' => 0.38, 'pref' => 0.12, 'prestasi' => 0.05, 'cita_cita' => 0.03],
|
||||
'match_prob' => ['nilai' => 0.82, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.71, 'cita_cita' => 0.85],
|
||||
|
|
@ -64,8 +66,8 @@
|
|||
'Kesehatan' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Pelayanan & Kesehatan',
|
||||
'pref' => ['Praktik Langsung', 'DuDi', 'Project Based'],
|
||||
'cita_cita_keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis'],
|
||||
'pref' => ['Kesehatan & Ilmu Hayat'],
|
||||
'cita_cita_keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis', 'farmasi', 'rekam medis', 'kesehatan masyarakat'],
|
||||
'skills_required' => ['Komunikasi', 'Empati', 'Presisi Medis'],
|
||||
'weights' => ['nilai' => 0.45, 'minat' => 0.35, 'pref' => 0.10, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.90, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.75, 'cita_cita' => 0.90],
|
||||
|
|
@ -73,8 +75,8 @@
|
|||
'Bahasa, Komunikasi, dan Pariwisata' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Umum',
|
||||
'pref' => ['Project Based', 'DuDi', 'Praktik Langsung'],
|
||||
'cita_cita_keywords' => ['tour guide', 'pariwisata', 'bahasa', 'komunikasi', 'jurnalis', 'marketing'],
|
||||
'pref' => ['Sosial & Humaniora', 'Bisnis & Manajemen'],
|
||||
'cita_cita_keywords' => ['tour guide', 'pariwisata', 'bahasa', 'komunikasi', 'jurnalis', 'marketing', 'public relation', 'content creator', 'hospitality'],
|
||||
'skills_required' => ['Komunikasi', 'Bahasa', 'Kepribadian'],
|
||||
'weights' => ['nilai' => 0.30, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.08, 'cita_cita' => 0.07],
|
||||
'match_prob' => ['nilai' => 0.70, 'minat' => 0.85, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
|
|
@ -82,20 +84,21 @@
|
|||
'Bisnis' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Manajemen & Bisnis',
|
||||
'pref' => ['Project Based', 'DuDi', 'Blended'],
|
||||
'cita_cita_keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales'],
|
||||
'pref' => ['Bisnis & Manajemen'],
|
||||
'cita_cita_keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales', 'akuntan', 'keuangan', 'bank'],
|
||||
'skills_required' => ['Manajemen', 'Leadership', 'Keuangan'],
|
||||
'weights' => ['nilai' => 0.35, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'match_prob' => ['nilai' => 0.75, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
],
|
||||
],
|
||||
|
||||
// Vocational Learning Preference Mapping
|
||||
// Mapping preferensi studi sesuai opsi input form rekomendasi
|
||||
'pref_mapping' => [
|
||||
'Praktik Langsung' => ['weight' => 1.0, 'score' => 0.95],
|
||||
'DuDi' => ['weight' => 0.95, 'score' => 0.90],
|
||||
'Project Based' => ['weight' => 0.90, 'score' => 0.85],
|
||||
'Blended' => ['weight' => 0.80, 'score' => 0.75],
|
||||
'Sains & Teknologi' => ['weight' => 1.0, 'score' => 0.95],
|
||||
'Pertanian & Lingkungan' => ['weight' => 0.95, 'score' => 0.90],
|
||||
'Kesehatan & Ilmu Hayat' => ['weight' => 0.95, 'score' => 0.90],
|
||||
'Bisnis & Manajemen' => ['weight' => 0.90, 'score' => 0.85],
|
||||
'Sosial & Humaniora' => ['weight' => 0.85, 'score' => 0.80],
|
||||
],
|
||||
|
||||
// Category mapping untuk nilai
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ class DatabaseSeeder extends Seeder
|
|||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// \App\Models\User::factory(10)->create();
|
||||
|
||||
// \App\Models\User::factory()->create([
|
||||
// 'name' => 'Test User',
|
||||
// 'email' => 'test@example.com',
|
||||
// ]);
|
||||
// Seeder inti untuk kebutuhan aplikasi
|
||||
// Jalankan otomatis saat migrate:fresh --seed
|
||||
$this->call([
|
||||
AdminSeeder::class,
|
||||
PolijeMajorSeeder::class,
|
||||
// AlumniSeeder::class, // Aktifkan jika butuh data evaluasi alumni
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ public function run(): void
|
|||
$jurusans = [
|
||||
[
|
||||
'nama_jurusan' => 'Produksi Pertanian',
|
||||
'deskripsi' => 'Jurusan yang mempelajari teknik budidaya tanaman, pengelolaan lahan pertanian, dan produksi hasil pertanian secara modern.',
|
||||
'keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman', 'budidaya', 'agronomi', 'tanam', 'bercocok tanam', 'alam', 'hortikultura', 'pupuk', 'bibit'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari budidaya tanaman, pengelolaan lahan, dan produksi hasil pertanian modern, termasuk bidang turunan yang terkait dengan agronomi, pangan, dan lingkungan.',
|
||||
'keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman', 'budidaya', 'agronomi', 'tanam', 'bercocok tanam', 'alam', 'hortikultura', 'pupuk', 'bibit', 'agroteknologi', 'perkebunan', 'pangan', 'ketahanan pangan', 'hidroponik', 'organik'],
|
||||
'preferensi_studi' => ['Pertanian & Lingkungan'],
|
||||
'bobot_mapel' => [
|
||||
'biologi' => 0.40, 'kimia' => 0.30, 'fisika' => 0.15, 'mtk' => 0.15,
|
||||
|
|
@ -23,8 +23,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Teknologi Pertanian',
|
||||
'deskripsi' => 'Jurusan yang mengintegrasikan teknologi dengan pertanian, meliputi mekanisasi pertanian, pengolahan hasil pertanian, dan inovasi teknologi pangan.',
|
||||
'keywords' => ['teknologi pertanian', 'mesin pertanian', 'inovasi', 'otomasi', 'pengolahan pangan', 'pangan', 'mekanisasi', 'teknologi pangan', 'alat pertanian', 'rekayasa'],
|
||||
'deskripsi' => 'Jurusan yang mengintegrasikan teknologi dengan pertanian, meliputi mekanisasi, pengolahan hasil, otomasi, dan inovasi teknologi pangan serta sistem produksi modern.',
|
||||
'keywords' => ['teknologi pertanian', 'mesin pertanian', 'inovasi', 'otomasi', 'pengolahan pangan', 'pangan', 'mekanisasi', 'teknologi pangan', 'alat pertanian', 'rekayasa', 'iot pertanian', 'smart farming', 'digital farming', 'kontrol kualitas', 'proses produksi'],
|
||||
'preferensi_studi' => ['Sains & Teknologi', 'Pertanian & Lingkungan'],
|
||||
'bobot_mapel' => [
|
||||
'fisika' => 0.35, 'mtk' => 0.30, 'kimia' => 0.20, 'biologi' => 0.15,
|
||||
|
|
@ -34,8 +34,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Peternakan',
|
||||
'deskripsi' => 'Jurusan yang mempelajari pengelolaan dan pemeliharaan ternak, nutrisi hewan, reproduksi, dan pengolahan produk peternakan.',
|
||||
'keywords' => ['ternak', 'hewan', 'peternakan', 'peternak', 'sapi', 'ayam', 'unggas', 'kambing', 'susu', 'pakan', 'nutrisi hewan', 'veteriner', 'ikan', 'aquaculture'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari pengelolaan ternak, nutrisi hewan, reproduksi, dan pengolahan produk peternakan, termasuk kewirausahaan dan teknologi peternakan terapan.',
|
||||
'keywords' => ['ternak', 'hewan', 'peternakan', 'peternak', 'sapi', 'ayam', 'unggas', 'kambing', 'susu', 'pakan', 'nutrisi hewan', 'veteriner', 'ikan', 'aquaculture', 'budidaya hewan', 'farm management', 'kesehatan hewan', 'produksi ternak'],
|
||||
'preferensi_studi' => ['Pertanian & Lingkungan', 'Kesehatan & Ilmu Hayat'],
|
||||
'bobot_mapel' => [
|
||||
'biologi' => 0.45, 'kimia' => 0.25, 'fisika' => 0.15, 'mtk' => 0.15,
|
||||
|
|
@ -45,8 +45,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Manajemen Agribisnis',
|
||||
'deskripsi' => 'Jurusan yang menggabungkan ilmu pertanian dan bisnis, meliputi pemasaran hasil pertanian, manajemen usaha tani, dan kewirausahaan agribisnis.',
|
||||
'keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha', 'dagang', 'jual', 'pemasaran', 'kewirausahaan', 'manajemen', 'ekonomi pertanian', 'pasar'],
|
||||
'deskripsi' => 'Jurusan yang menggabungkan ilmu pertanian dan bisnis, meliputi manajemen usaha, pemasaran hasil, rantai pasok, dan kewirausahaan agribisnis.',
|
||||
'keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha', 'dagang', 'jual', 'pemasaran', 'kewirausahaan', 'manajemen', 'ekonomi pertanian', 'pasar', 'supply chain', 'logistik', 'analisis pasar', 'branding produk'],
|
||||
'preferensi_studi' => ['Bisnis & Manajemen', 'Pertanian & Lingkungan'],
|
||||
'bobot_mapel' => [
|
||||
'mtk' => 0.35, 'biologi' => 0.25, 'kimia' => 0.20, 'fisika' => 0.20,
|
||||
|
|
@ -56,8 +56,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Teknologi Informasi',
|
||||
'deskripsi' => 'Jurusan yang mempelajari pengembangan perangkat lunak, jaringan komputer, keamanan siber, dan teknologi digital.',
|
||||
'keywords' => ['programmer', 'developer', 'coding', 'software', 'web', 'aplikasi', 'komputer', 'it', 'jaringan', 'hacker', 'game', 'data', 'ai', 'robot', 'ngoding', 'laptop', 'teknologi', 'digital', 'internet', 'programming', 'desain grafis'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari pengembangan perangkat lunak, data, jaringan, keamanan siber, dan ekosistem teknologi digital, termasuk bidang turunan komputasi terapan.',
|
||||
'keywords' => ['programmer', 'developer', 'coding', 'software', 'web', 'aplikasi', 'komputer', 'it', 'jaringan', 'hacker', 'game', 'data', 'ai', 'robot', 'ngoding', 'laptop', 'teknologi', 'digital', 'internet', 'programming', 'desain grafis', 'ui ux', 'mobile app', 'cloud', 'database', 'machine learning'],
|
||||
'preferensi_studi' => ['Sains & Teknologi'],
|
||||
'bobot_mapel' => [
|
||||
'mtk' => 0.45, 'fisika' => 0.25, 'kimia' => 0.15, 'biologi' => 0.15,
|
||||
|
|
@ -67,8 +67,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Teknik',
|
||||
'deskripsi' => 'Jurusan yang mempelajari mesin, kelistrikan, elektronika, dan otomasi industri.',
|
||||
'keywords' => ['mesin', 'bengkel', 'listrik', 'las', 'robot', 'motor', 'teknik', 'otomasi', 'elektronik', 'instalasi', 'panel', 'mekanik', 'industri', 'manufaktur', 'pabrik', 'bangunan', 'konstruksi', 'sipil', 'energi'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari mesin, kelistrikan, elektronika, otomasi, dan sistem teknik industri dengan pendekatan praktik dan pemecahan masalah teknis.',
|
||||
'keywords' => ['mesin', 'bengkel', 'listrik', 'las', 'robot', 'motor', 'teknik', 'otomasi', 'elektronik', 'instalasi', 'panel', 'mekanik', 'industri', 'manufaktur', 'pabrik', 'bangunan', 'konstruksi', 'sipil', 'energi', 'maintenance', 'mekatronika', 'instrumentasi', 'quality control'],
|
||||
'preferensi_studi' => ['Sains & Teknologi'],
|
||||
'bobot_mapel' => [
|
||||
'fisika' => 0.40, 'mtk' => 0.35, 'kimia' => 0.15, 'biologi' => 0.10,
|
||||
|
|
@ -78,8 +78,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Kesehatan',
|
||||
'deskripsi' => 'Jurusan yang mempelajari ilmu kesehatan, gizi, rekam medis, dan pelayanan kesehatan masyarakat.',
|
||||
'keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis', 'obat', 'rumah sakit', 'klinik', 'farmasi', 'nutrisi', 'sanitasi', 'rawat', 'sehat'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari ilmu kesehatan terapan, gizi, rekam medis, dan pelayanan kesehatan masyarakat, termasuk aspek promotif dan preventif.',
|
||||
'keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis', 'obat', 'rumah sakit', 'klinik', 'farmasi', 'nutrisi', 'sanitasi', 'rawat', 'sehat', 'kesehatan masyarakat', 'laboratorium', 'diagnostik', 'wellness'],
|
||||
'preferensi_studi' => ['Kesehatan & Ilmu Hayat'],
|
||||
'bobot_mapel' => [
|
||||
'biologi' => 0.40, 'kimia' => 0.35, 'mtk' => 0.15, 'fisika' => 0.10,
|
||||
|
|
@ -89,8 +89,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Bahasa, Komunikasi, dan Pariwisata',
|
||||
'deskripsi' => 'Jurusan yang mempelajari bahasa asing, komunikasi, perhotelan, dan industri pariwisata.',
|
||||
'keywords' => ['bahasa', 'komunikasi', 'pariwisata', 'tour guide', 'hotel', 'jurnalis', 'marketing', 'inggris', 'penerjemah', 'travel', 'wisata', 'hospitality', 'public speaking', 'media', 'broadcasting'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari bahasa, komunikasi, perhotelan, layanan publik, dan industri pariwisata dengan orientasi pada kompetensi komunikasi profesional.',
|
||||
'keywords' => ['bahasa', 'komunikasi', 'pariwisata', 'tour guide', 'hotel', 'jurnalis', 'marketing', 'inggris', 'penerjemah', 'travel', 'wisata', 'hospitality', 'public speaking', 'media', 'broadcasting', 'content creator', 'humas', 'event', 'pelayanan tamu'],
|
||||
'preferensi_studi' => ['Sosial & Humaniora', 'Bisnis & Manajemen'],
|
||||
'bobot_mapel' => [
|
||||
'biologi' => 0.20, 'kimia' => 0.20, 'fisika' => 0.20, 'mtk' => 0.40,
|
||||
|
|
@ -100,8 +100,8 @@ public function run(): void
|
|||
],
|
||||
[
|
||||
'nama_jurusan' => 'Bisnis',
|
||||
'deskripsi' => 'Jurusan yang mempelajari akuntansi, manajemen bisnis, perbankan, dan administrasi niaga.',
|
||||
'keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales', 'kantor', 'keuangan', 'bank', 'akuntansi', 'hitung', 'administrasi', 'perbankan', 'ekonomi', 'uang', 'investasi', 'pajak'],
|
||||
'deskripsi' => 'Jurusan yang mempelajari akuntansi, manajemen bisnis, perbankan, keuangan, dan administrasi niaga, termasuk analisis data bisnis dan pengambilan keputusan.',
|
||||
'keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales', 'kantor', 'keuangan', 'bank', 'akuntansi', 'hitung', 'administrasi', 'perbankan', 'ekonomi', 'uang', 'investasi', 'pajak', 'wirausaha', 'audit', 'finance', 'analisis bisnis'],
|
||||
'preferensi_studi' => ['Bisnis & Manajemen'],
|
||||
'bobot_mapel' => [
|
||||
'mtk' => 0.45, 'fisika' => 0.20, 'kimia' => 0.15, 'biologi' => 0.20,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
|
||||
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value=":memory:"/>
|
||||
<env name="MAIL_MAILER" value="array"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title', 'Admin Panel') - SPK Jurusan Kuliah</title>
|
||||
<title>@yield('title', 'Admin Panel') - SPK Jurusan Polije</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon { background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%); }
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
</button>
|
||||
<div>
|
||||
<h1 class="text-lg sm:text-xl md:text-2xl font-bold">🔧 Admin Panel</h1>
|
||||
<p class="text-xs text-gray-200 font-semibold">Sistem Pemilihan Jurusan Kuliah</p>
|
||||
<p class="text-xs text-gray-200 font-semibold">Sistem Pemilihan Jurusan Politeknik Negeri Jember</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title', 'Panel Guru BK') - SPK Jurusan Kuliah</title>
|
||||
<title>@yield('title', 'Panel Guru BK') - SPK Jurusan Polije</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-bk { background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); }
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
</button>
|
||||
<div>
|
||||
<h1 class="text-lg sm:text-xl md:text-2xl font-bold">📋 Panel Guru BK</h1>
|
||||
<p class="text-xs text-teal-100 font-semibold">Sistem Pemilihan Jurusan Kuliah</p>
|
||||
<p class="text-xs text-teal-100 font-semibold">Sistem Pemilihan Jurusan Politeknik Negeri Jember</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
<div class="container mx-auto px-4 sm:px-6 py-4 sm:py-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 sm:gap-4">
|
||||
<div>
|
||||
<h1 class="text-xl sm:text-2xl md:text-3xl font-bold">Konsultasi BK Virtual</h1>
|
||||
<p class="text-xs sm:text-sm text-yellow-300 font-semibold mt-1">Konseling Pemilihan Jurusan Kuliah</p>
|
||||
<p class="text-xs sm:text-sm text-yellow-300 font-semibold mt-1">Konseling Pemilihan Jurusan Politeknik Negeri Jember</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 sm:gap-4 w-full sm:w-auto">
|
||||
<a href="{{ route('chatbot.index') }}" class="block sm:inline-block flex-1 sm:flex-none text-center bg-white text-maroon font-bold py-2 px-3 sm:px-4 rounded-lg hover:bg-gray-100 transition text-xs sm:text-sm">
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
<li class="text-gray-700">• Aku bingung pilih jurusan</li>
|
||||
<li class="text-gray-700">• Skill apa yang dibutuhkan?</li>
|
||||
<li class="text-gray-700">• Bedanya IPA dan IPS?</li>
|
||||
<li class="text-gray-700">• Tips sukses di kampus?</li>
|
||||
<li class="text-gray-700">• Tips sukses kuliah di Polije?</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -218,7 +218,7 @@ class="gradient-maroon text-white font-bold py-2 px-4 sm:px-6 rounded-lg hover:o
|
|||
// Melanjutkan sesi lama — tampilkan info lanjutan
|
||||
document.getElementById('initialGreeting').textContent = sapaan + '. Anda melanjutkan sesi konsultasi sebelumnya. Silakan lanjutkan pertanyaan Anda.';
|
||||
} else {
|
||||
document.getElementById('initialGreeting').textContent = sapaan + '. Saya adalah konselor BK virtual SMA Bima Ambulu. Saya siap membantu Anda dalam pemilihan jurusan kuliah, informasi prospek karier, maupun konsultasi lainnya terkait pendidikan tinggi. Silakan sampaikan pertanyaan Anda.';
|
||||
document.getElementById('initialGreeting').textContent = sapaan + '. Saya adalah konselor BK virtual SMA Bima Ambulu. Saya siap membantu Anda dalam pemilihan jurusan Politeknik Negeri Jember, informasi prospek karier, maupun konsultasi lanjutan studi. Silakan sampaikan pertanyaan Anda.';
|
||||
}
|
||||
})();
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,9 @@
|
|||
<div class="bg-maroon-light p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Prestasi</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">
|
||||
@if($prestasiScore >= 0.8)
|
||||
@if(!($isPrestasiFilled ?? true))
|
||||
Tidak Dihitung
|
||||
@elseif($prestasiScore >= 0.8)
|
||||
Tinggi
|
||||
@elseif($prestasiScore >= 0.6)
|
||||
Sedang
|
||||
|
|
@ -205,8 +207,16 @@
|
|||
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Prestasi — P(prestasi|H) × w=0.05</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">{{ number_format(($detail['prestasi'] ?? 0) * 100, 1) }}%</span>
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">
|
||||
Prestasi — P(prestasi|H) × w={{ ($isPrestasiFilled ?? true) ? '0.05' : '0.00' }}
|
||||
</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">
|
||||
@if(!($isPrestasiFilled ?? true))
|
||||
Tidak dihitung
|
||||
@else
|
||||
{{ number_format(($detail['prestasi'] ?? 0) * 100, 1) }}%
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-300 rounded-full h-2">
|
||||
<div class="gradient-maroon h-2 rounded-full" style="width: {{ number_format(($detail['prestasi'] ?? 0) * 100, 1) }}%"></div>
|
||||
|
|
@ -338,8 +348,14 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-between items-center text-xs mt-2">
|
||||
<span class="text-gray-600">🏆 Prestasi (5%)</span>
|
||||
<span class="font-semibold text-maroon">{{ number_format(($rec['detail']['prestasi'] ?? 0) * 100, 1) }}%</span>
|
||||
<span class="text-gray-600">🏆 Prestasi ({{ ($isPrestasiFilled ?? true) ? '5%' : '0%' }})</span>
|
||||
<span class="font-semibold text-maroon">
|
||||
@if(!($isPrestasiFilled ?? true))
|
||||
Tidak dihitung
|
||||
@else
|
||||
{{ number_format(($rec['detail']['prestasi'] ?? 0) * 100, 1) }}%
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded h-1.5">
|
||||
<div class="bg-green-500 rounded h-1.5 transition-all" style="width: {{ number_format(($rec['detail']['prestasi'] ?? 0) * 100, 1) }}%"></div>
|
||||
|
|
@ -413,7 +429,7 @@
|
|||
<!-- Info Metode -->
|
||||
<div class="mt-6 sm:mt-8 p-3 sm:p-4 bg-white rounded-lg border border-gray-200 shadow-sm">
|
||||
<p class="text-xs sm:text-sm text-gray-600">
|
||||
<strong>Metode:</strong> Sistem menggunakan algoritma Weighted Naive Bayes dengan 5 fitur berbobot: Nilai Akademik (w=0.40), Minat (w=0.35), Preferensi Studi (w=0.15), Cita-cita (w=0.05), Prestasi (w=0.05). Rumus: P(H|X) ∝ P(H) × ∏ P(Xi|H)<sup>wi</sup>, kemudian dinormalisasi menggunakan softmax.
|
||||
<strong>Metode:</strong> Sistem menggunakan algoritma Weighted Naive Bayes dengan 5 fitur berbobot: Nilai Akademik (w=0.40), Minat (w=0.35), Preferensi Studi (w=0.15), Cita-cita (w=0.05), Prestasi (w=0.05). Jika prestasi tidak diisi, atribut prestasi tidak dihitung (w=0.00) dan bobot atribut lain dinormalisasi. Rumus: P(H|X) ∝ P(H) × ∏ P(Xi|H)<sup>wi</sup>, kemudian dinormalisasi menggunakan softmax.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@
|
|||
<p class="text-xs sm:text-sm md:text-base text-gray-700 mb-2">
|
||||
Silakan isi data berikut dengan jujur agar sistem dapat memberikan rekomendasi yang akurat.
|
||||
</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-2">
|
||||
Perhitungan menggunakan algoritma <strong>Naive Bayes berbobot</strong> berdasarkan 5 atribut input: <strong>nilai akademik (40%)</strong>, <strong>minat (35%)</strong>, <strong>preferensi studi lanjutan (15%)</strong>, <strong>cita-cita (5%)</strong>, dan <strong>prestasi (5%)</strong>.
|
||||
</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600">
|
||||
Sistem akan menganalisis data Anda dan menampilkan ranking <strong>9 jurusan</strong> yang tersedia di Politeknik Negeri Jember.
|
||||
</p>
|
||||
|
|
@ -189,19 +192,19 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">3. Preferensi Studi Lanjutan <span class="text-red-500">*</span></h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">
|
||||
Preferensi studi lanjutan adalah kecenderungan pilihan Anda terhadap rumpun bidang studi yang ingin ditempuh setelah lulus, berdasarkan pertimbangan minat, bakat, kemampuan, dan prospek karir di masa depan.
|
||||
Bagian ini menanyakan arah lanjutan studi Anda setelah lulus SMA, yaitu ingin melanjutkan ke rumpun jurusan Politeknik Negeri Jember yang mana. Jadi fokusnya adalah tujuan jalur jurusan yang ingin dituju, bukan metode belajar.
|
||||
</p>
|
||||
<div>
|
||||
<label for="pref_studi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Rumpun Bidang Studi</label>
|
||||
<label for="pref_studi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Arah Rumpun Jurusan Tujuan</label>
|
||||
<select id="pref_studi" name="pref_studi" class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm @error('pref_studi') border-red-500 @enderror" required>
|
||||
<option value="">-- Pilih Rumpun Bidang Studi --</option>
|
||||
<option value="Sains & Teknologi" {{ old('pref_studi') == 'Sains & Teknologi' ? 'selected' : '' }}>Sains & Teknologi</option>
|
||||
<option value="Pertanian & Lingkungan" {{ old('pref_studi') == 'Pertanian & Lingkungan' ? 'selected' : '' }}>Pertanian & Lingkungan</option>
|
||||
<option value="Kesehatan & Ilmu Hayat" {{ old('pref_studi') == 'Kesehatan & Ilmu Hayat' ? 'selected' : '' }}>Kesehatan & Ilmu Hayat</option>
|
||||
<option value="Bisnis & Manajemen" {{ old('pref_studi') == 'Bisnis & Manajemen' ? 'selected' : '' }}>Bisnis & Manajemen</option>
|
||||
<option value="Sosial & Humaniora" {{ old('pref_studi') == 'Sosial & Humaniora' ? 'selected' : '' }}>Sosial, Bahasa & Humaniora</option>
|
||||
<option value="">-- Pilih Arah Rumpun Jurusan --</option>
|
||||
<option value="Sains & Teknologi" {{ old('pref_studi') == 'Sains & Teknologi' ? 'selected' : '' }}>Sains & Teknologi (contoh: TI, Teknik)</option>
|
||||
<option value="Pertanian & Lingkungan" {{ old('pref_studi') == 'Pertanian & Lingkungan' ? 'selected' : '' }}>Pertanian & Lingkungan (contoh: Produksi/Teknologi Pertanian)</option>
|
||||
<option value="Kesehatan & Ilmu Hayat" {{ old('pref_studi') == 'Kesehatan & Ilmu Hayat' ? 'selected' : '' }}>Kesehatan & Ilmu Hayat (contoh: rumpun Kesehatan)</option>
|
||||
<option value="Bisnis & Manajemen" {{ old('pref_studi') == 'Bisnis & Manajemen' ? 'selected' : '' }}>Bisnis & Manajemen (contoh: Akuntansi, Manajemen Agribisnis)</option>
|
||||
<option value="Sosial & Humaniora" {{ old('pref_studi') == 'Sosial & Humaniora' ? 'selected' : '' }}>Sosial & Humaniora (contoh: Bahasa, Komunikasi, Pariwisata)</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilih rumpun studi yang paling mendekati kecenderungan Anda</p>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilih rumpun yang paling menggambarkan jurusan Polije yang ingin Anda tuju setelah lulus.</p>
|
||||
@error('pref_studi')
|
||||
<span class="text-red-500 text-xs mt-1">{{ $message }}</span>
|
||||
@enderror
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@
|
|||
<div>
|
||||
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6">Tentukan Pilihan Jurusan dengan Bijak</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-3 sm:mb-4 text-yellow-100">
|
||||
Hai, teman-teman siswa SMA Bima Ambulu! Memilih jurusan kuliah itu keputusan penting yang akan menentukan masa depan kalian. Sistem ini akan membantu menemukan jurusan yang sesuai dengan kemampuan dan minat kalian.
|
||||
Selamat datang, siswa SMA Bima Ambulu. Memilih jurusan di Politeknik Negeri Jember adalah keputusan penting yang mempengaruhi masa depan. Sistem ini membantu Anda menentukan pilihan jurusan yang sesuai dengan kemampuan dan minat.
|
||||
</p>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-yellow-100">
|
||||
Sistem ini menganalisis 5 aspek penting dalam diri kalian untuk memberikan rekomendasi yang akurat dan personal.
|
||||
Sistem menganalisis 5 aspek utama untuk memberikan rekomendasi jurusan Politeknik Negeri Jember (Polije) yang akurat dan personal.
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4">
|
||||
<a href="{{ route('login') }}" class="inline-block bg-yellow-400 text-maroon font-bold py-2 sm:py-3 px-6 sm:px-8 rounded-lg hover:bg-yellow-300 transition text-sm sm:text-base text-center">Mulai Analisis</a>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
<div class="bg-white rounded-lg p-6 sm:p-8 shadow-2xl w-full max-w-sm text-center text-maroon">
|
||||
<div class="text-5xl sm:text-6xl mb-4">✨</div>
|
||||
<h3 class="text-xl sm:text-2xl font-bold mb-3 sm:mb-4">9 Kategori Jurusan</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-4 sm:mb-6">Pilihan jurusan dari berbagai bidang: pertanian, teknologi, kesehatan, hingga bisnis</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-4 sm:mb-6">Pilihan jurusan Politeknik Negeri Jember dari berbagai bidang: pertanian, teknologi, kesehatan, hingga bisnis</p>
|
||||
<div class="bg-yellow-100 rounded-lg p-4">
|
||||
<p class="text-xs sm:text-sm font-semibold">Temukan Ranking Jurusan yang Paling Cocok buat Kamu</p>
|
||||
</div>
|
||||
|
|
@ -93,22 +93,22 @@
|
|||
<!-- MENGAPA SISTEM INI PENTING -->
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-white">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-8 sm:mb-12">Kenapa Perlu Pakai Sistem Ini?</h2>
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-8 sm:mb-12">Mengapa Perlu Menggunakan Sistem Ini?</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8">
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">🤖</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Analisis Berbasis Data</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Menggunakan AI untuk menganalisis profil akademik dan non-akademik kalian secara detail</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Menggunakan pendekatan berbasis data untuk menganalisis profil akademik dan non-akademik secara detail</p>
|
||||
</div>
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">🎯</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Pendekatan Menyeluruh</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Nggak cuma dari nilai aja, tapi juga dari minat, gaya belajar, impian karir, dan prestasi</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Tidak hanya berdasarkan nilai, tetapi juga minat, preferensi studi lanjutan, cita-cita karir, dan prestasi</p>
|
||||
</div>
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">💡</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Rekomendasi Akurat</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Membantu kalian memilih jurusan dengan lebih yakin berdasarkan data yang objektif</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Membantu Anda memilih jurusan dengan lebih yakin berdasarkan data yang objektif</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -119,14 +119,14 @@
|
|||
<section class="py-8 sm:py-12 md:py-16 bg-cream">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">5 Aspek yang Dianalisis Sistem</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Sistem ini menganalisis 5 aspek penting dalam diri kalian untuk memberikan rekomendasi jurusan yang tepat dan personal.</p>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Sistem ini menganalisis 5 aspek penting dalam profil Anda untuk memberikan rekomendasi jurusan yang tepat dan personal.</p>
|
||||
<div class="max-w-4xl mx-auto space-y-4 sm:space-y-6">
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">1</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">📚 Nilai Akademik (Bobot 40%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Prestasi kalian dalam mata pelajaran utama (IPA atau IPS) menunjukkan kemampuan dasar untuk sukses di jurusan tertentu</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Nilai Anda pada mata pelajaran utama (IPA atau IPS) menunjukkan kemampuan dasar untuk sukses di jurusan tertentu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -134,8 +134,8 @@
|
|||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">2</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">❤️ Minat & Gaya Belajar (Bobot 35%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Minat kalian terhadap bidang tertentu sangat menentukan kesuksesan dalam perkuliahan nanti</p>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">❤️ Minat & Passion (Bobot 35%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Minat Anda terhadap bidang atau kegiatan tertentu sangat menentukan keberhasilan dalam perkuliahan</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,8 +143,8 @@
|
|||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">3</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🎓 Preferensi Metode Belajar (Bobot 15%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Cara belajar yang kalian sukai - praktik langsung, project based, kerjasama industri, atau blended learning</p>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🎓 Preferensi Studi Lanjutan (Bobot 15%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Pilihan rumpun bidang studi (Sains & Teknologi, Pertanian, Kesehatan, Bisnis, atau Sosial & Humaniora) yang sesuai dengan kecenderungan dan prospek karir Anda</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -153,7 +153,7 @@
|
|||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">4</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🚀 Impian dan Tujuan Karir (Bobot 5%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Cita-cita dan target karir kalian membantu mencocokkan pilihan jurusan dengan jalur profesional yang diinginkan</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Cita-cita dan target karir Anda membantu mencocokkan pilihan jurusan dengan jalur profesional yang diinginkan</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">5</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🏆 Prestasi dan Kegiatan (Bobot 5%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Pencapaian kalian dalam kompetisi akademik maupun kegiatan ekstra menunjukkan potensi dan dedikasi khusus</p>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Pencapaian dalam kompetisi akademik maupun kegiatan non-akademik menunjukkan potensi dan dedikasi</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -174,7 +174,7 @@
|
|||
<section class="py-8 sm:py-12 md:py-16 bg-white">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">9 Kategori Jurusan yang Bisa Dipilih</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Ada banyak pilihan jurusan dari berbagai bidang. Sistem ini akan menganalisis profil kalian dan merekomendasikan jurusan mana yang paling cocok berdasarkan nilai, minat, dan potensi kalian.</p>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Tersedia banyak pilihan jurusan dari berbagai bidang. Sistem ini akan menganalisis profil Anda dan merekomendasikan jurusan yang paling sesuai berdasarkan nilai, minat, dan potensi.</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">🌾</div>
|
||||
|
|
@ -228,23 +228,23 @@
|
|||
<!-- HOW IT WORKS -->
|
||||
<section id="how-it-works" class="py-8 sm:py-12 md:py-16 bg-cream">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">Cara Pakai Sistemnya</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Cuma 4 langkah mudah untuk menemukan rekomendasi jurusan yang paling cocok dengan profil dan impian kalian.</p>
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">Cara Menggunakan Sistem</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Empat langkah mudah untuk menemukan rekomendasi jurusan yang paling sesuai dengan profil dan impian Anda.</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6">
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">1</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Daftar Akun</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Buat akun pakai email, NIS, dan data diri kalian</p>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Buat akun menggunakan email, NIS, dan data diri</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">2</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Isi Data</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Lengkapi 5 aspek penting tentang diri kalian</p>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Lengkapi 5 aspek penting pada profil Anda</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">3</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Proses AI</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Sistem memproses data kalian dengan algoritma cerdas</p>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Sistem memproses data Anda dengan algoritma yang terstruktur</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">4</div>
|
||||
|
|
@ -258,8 +258,8 @@
|
|||
<!-- CALL TO ACTION -->
|
||||
<section class="py-8 sm:py-12 md:py-16 gradient-maroon text-white">
|
||||
<div class="container mx-auto px-4 sm:px-6 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold mb-4 sm:mb-6">Yuk, Temukan Jurusan yang Cocok!</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-yellow-100 max-w-2xl mx-auto">Jangan buat keputusan penting sendirian. Pakai sistem ini untuk mendapatkan rekomendasi jurusan yang akurat berdasarkan nilai, minat, dan cita-cita kalian!</p>
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold mb-4 sm:mb-6">Temukan Jurusan Polije yang Paling Cocok</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-yellow-100 max-w-2xl mx-auto">Gunakan sistem ini untuk memperoleh rekomendasi jurusan Politeknik Negeri Jember yang akurat berdasarkan nilai, minat, dan cita-cita Anda.</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center">
|
||||
<a href="{{ route('register') }}" class="inline-block bg-yellow-400 text-maroon font-bold py-2 sm:py-3 px-6 sm:px-10 rounded-lg hover:bg-yellow-300 transition text-sm sm:text-base text-center">Daftar Sekarang</a>
|
||||
<a href="{{ route('login') }}" class="inline-block border-2 border-yellow-400 text-yellow-300 font-bold py-2 sm:py-3 px-6 sm:px-10 rounded-lg hover:bg-yellow-400 hover:text-maroon transition text-sm sm:text-base text-center">Login</a>
|
||||
|
|
@ -272,7 +272,7 @@
|
|||
<div class="container mx-auto px-4 sm:px-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
||||
<div>
|
||||
<h3 class="text-base sm:text-lg font-bold text-yellow-400 mb-3 sm:mb-4">Untuk Siswa SMA Bima Ambulu</h3>
|
||||
<p class="text-xs sm:text-sm text-yellow-100">Sistem ini dikembangkan khusus untuk membantu teman-teman siswa SMA Bima Ambulu dalam menemukan jurusan kuliah yang paling cocok dengan minat dan kemampuan kalian.</p>
|
||||
<p class="text-xs sm:text-sm text-yellow-100">Sistem ini dikembangkan khusus untuk membantu siswa SMA Bima Ambulu menemukan jurusan Politeknik Negeri Jember yang paling sesuai dengan minat dan kemampuan.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base sm:text-lg font-bold text-yellow-400 mb-3 sm:mb-4">Kontak SMA Bima Ambulu</h3>
|
||||
|
|
@ -293,7 +293,7 @@
|
|||
</div>
|
||||
<div class="border-t border-yellow-300 mt-6 sm:mt-8 pt-4 sm:pt-6 text-center text-xs sm:text-sm text-yellow-100">
|
||||
<p>© 2026 Sistem Pemilihan Jurusan</p>
|
||||
<p class="mt-1 sm:mt-2">Membantu Siswa SMA Bima Ambulu Memilih Jurusan Kuliah yang Tepat</p>
|
||||
<p class="mt-1 sm:mt-2">Membantu Siswa SMA Bima Ambulu Memilih Jurusan Politeknik Negeri Jember yang Tepat</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue