Spaces:
Running
Running
{% extends 'dashboard/base.html' %} {% block title %}Klasifikasi{% endblock | |
title %} {% block content %} | |
<h1 class="app-page-title">Klasifikasi</h1> | |
<hr class="my-4" /> | |
<div class="row g-4 settings-section"> | |
<div class="col-12"> | |
<h3 class="section-title">Kelas</h3> | |
<div class="section-intro"> | |
Terdapat | |
<span class="text-unmuted">4 kelompok bidang keahlian </span> sebagai | |
kelas klasifikasi. | |
</div> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div | |
class="app-card app-card-basic d-flex flex-column align-items-start shadow-sm" | |
> | |
<div class="app-card-header p-3 border-bottom-0"> | |
<div class="row align-items-center gx-3"> | |
<div class="col-auto"> | |
<div class="app-icon-holder"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="16" | |
height="16" | |
fill="currentColor" | |
class="bi bi-code-square" | |
viewBox="0 0 16 16" | |
> | |
<path | |
d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z" | |
/> | |
<path | |
d="M6.854 4.646a.5.5 0 0 1 0 .708L4.207 8l2.647 2.646a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 0 1 .708 0m2.292 0a.5.5 0 0 0 0 .708L11.793 8l-2.647 2.646a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 0 0-.708 0" | |
/> | |
</svg> | |
</div> | |
<!--//icon-holder--> | |
</div> | |
<!--//col--> | |
<div class="col-auto"> | |
<h4 class="app-card-title">Rekayasa Perangkat Lunak</h4> | |
</div> | |
<!--//col--> | |
</div> | |
<!--//row--> | |
</div> | |
</div> | |
<!--//app-card--> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div | |
class="app-card app-card-basic d-flex flex-column align-items-start shadow-sm" | |
> | |
<div class="app-card-header p-3 border-bottom-0"> | |
<div class="row align-items-center gx-3"> | |
<div class="col-auto"> | |
<div class="app-icon-holder"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="16" | |
height="16" | |
fill="currentColor" | |
class="bi bi-robot" | |
viewBox="0 0 16 16" | |
> | |
<path | |
d="M6 12.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M3 8.062C3 6.76 4.235 5.765 5.53 5.886a26.6 26.6 0 0 0 4.94 0C11.765 5.765 13 6.76 13 8.062v1.157a.93.93 0 0 1-.765.935c-.845.147-2.34.346-4.235.346s-3.39-.2-4.235-.346A.93.93 0 0 1 3 9.219zm4.542-.827a.25.25 0 0 0-.217.068l-.92.9a25 25 0 0 1-1.871-.183.25.25 0 0 0-.068.495c.55.076 1.232.149 2.02.193a.25.25 0 0 0 .189-.071l.754-.736.847 1.71a.25.25 0 0 0 .404.062l.932-.97a25 25 0 0 0 1.922-.188.25.25 0 0 0-.068-.495c-.538.074-1.207.145-1.98.189a.25.25 0 0 0-.166.076l-.754.785-.842-1.7a.25.25 0 0 0-.182-.135" | |
/> | |
<path | |
d="M8.5 1.866a1 1 0 1 0-1 0V3h-2A4.5 4.5 0 0 0 1 7.5V8a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1v1a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1a1 1 0 0 0 1-1V9a1 1 0 0 0-1-1v-.5A4.5 4.5 0 0 0 10.5 3h-2zM14 7.5V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.5A3.5 3.5 0 0 1 5.5 4h5A3.5 3.5 0 0 1 14 7.5" | |
/> | |
</svg> | |
</div> | |
<!--//icon-holder--> | |
</div> | |
<!--//col--> | |
<div class="col-auto"> | |
<h4 class="app-card-title">Sistem Cerdas</h4> | |
</div> | |
<!--//col--> | |
</div> | |
<!--//row--> | |
</div> | |
</div> | |
<!--//app-card--> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div | |
class="app-card app-card-basic d-flex flex-column align-items-start shadow-sm" | |
> | |
<div class="app-card-header p-3 border-bottom-0"> | |
<div class="row align-items-center gx-3"> | |
<div class="col-auto"> | |
<div class="app-icon-holder"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="16" | |
height="16" | |
fill="currentColor" | |
class="bi bi-router" | |
viewBox="0 0 16 16" | |
> | |
<path | |
d="M5.525 3.025a3.5 3.5 0 0 1 4.95 0 .5.5 0 1 0 .707-.707 4.5 4.5 0 0 0-6.364 0 .5.5 0 0 0 .707.707" | |
/> | |
<path | |
d="M6.94 4.44a1.5 1.5 0 0 1 2.12 0 .5.5 0 0 0 .708-.708 2.5 2.5 0 0 0-3.536 0 .5.5 0 0 0 .707.707ZM2.5 11a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1m4.5-.5a.5.5 0 1 0 1 0 .5.5 0 0 0-1 0m2.5.5a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1m1.5-.5a.5.5 0 1 0 1 0 .5.5 0 0 0-1 0m2 0a.5.5 0 1 0 1 0 .5.5 0 0 0-1 0" | |
/> | |
<path | |
d="M2.974 2.342a.5.5 0 1 0-.948.316L3.806 8H1.5A1.5 1.5 0 0 0 0 9.5v2A1.5 1.5 0 0 0 1.5 13H2a.5.5 0 0 0 .5.5h2A.5.5 0 0 0 5 13h6a.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5h.5a1.5 1.5 0 0 0 1.5-1.5v-2A1.5 1.5 0 0 0 14.5 8h-2.306l1.78-5.342a.5.5 0 1 0-.948-.316L11.14 8H4.86zM14.5 9a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5z" | |
/> | |
<path d="M8.5 5.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0" /> | |
</svg> | |
</div> | |
<!--//icon-holder--> | |
</div> | |
<!--//col--> | |
<div class="col-auto"> | |
<h4 class="app-card-title">Jaringan & IoT</h4> | |
</div> | |
<!--//col--> | |
</div> | |
<!--//row--> | |
</div> | |
</div> | |
<!--//app-card--> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div | |
class="app-card app-card-basic d-flex flex-column align-items-start shadow-sm" | |
> | |
<div class="app-card-header p-3 border-bottom-0"> | |
<div class="row align-items-center gx-3"> | |
<div class="col-auto"> | |
<div class="app-icon-holder"> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width="16" | |
height="16" | |
fill="currentColor" | |
class="bi bi-easel2" | |
viewBox="0 0 16 16" | |
> | |
<path | |
fill-rule="evenodd" | |
d="M8 0a.5.5 0 0 1 .447.276L8.81 1h4.69A1.5 1.5 0 0 1 15 2.5V11h.5a.5.5 0 0 1 0 1h-2.86l.845 3.379a.5.5 0 0 1-.97.242L12.11 14H3.89l-.405 1.621a.5.5 0 0 1-.97-.242L3.36 12H.5a.5.5 0 0 1 0-1H1V2.5A1.5 1.5 0 0 1 2.5 1h4.691l.362-.724A.5.5 0 0 1 8 0M2 11h12V2.5a.5.5 0 0 0-.5-.5h-11a.5.5 0 0 0-.5.5zm9.61 1H4.39l-.25 1h7.72z" | |
/> | |
</svg> | |
</div> | |
<!--//icon-holder--> | |
</div> | |
<!--//col--> | |
<div class="col-auto"> | |
<h4 class="app-card-title">Multimedia & Teknologi: AI Game</h4> | |
</div> | |
<!--//col--> | |
</div> | |
<!--//row--> | |
</div> | |
</div> | |
<!--//app-card--> | |
</div> | |
</div> | |
<hr class="my-4" /> | |
<div class="row g-4 settings-section"> | |
<div class="col-12"> | |
<h3 class="section-title">Data</h3> | |
<div class="section-intro"> | |
Masukkan <span class="text-unmuted">abstrak dan kata kunci</span> Anda | |
sebagai data untuk diklasifikasikan. | |
</div> | |
</div> | |
<div class="col-12"> | |
<div class="app-card app-card-settings shadow-sm p-4"> | |
<div class="app-card-body"> | |
<form method="post" id="inference"> | |
<div class="mb-3"> | |
<div class="d-flex justify-content-between"> | |
<label for="abstrak" class="form-label">Abstrak</label> | |
<div id="wordCounter">0/350</div> | |
</div> | |
<textarea | |
id="abstrak" | |
class="form-control" | |
placeholder="Masukkan abstrak" | |
style="height: 160px" | |
required | |
></textarea> | |
</div> | |
<div class="mb-5"> | |
<label for="keywordInput" class="form-label">Kata Kunci</label> | |
<div class="d-flex"> | |
<input | |
type="text" | |
class="form-control" | |
id="keywordInput" | |
placeholder="Masukkan kata kunci" | |
style="width: 200px" | |
/> | |
<button | |
class="btn app-btn-secondary ms-2" | |
href="" | |
id="addKeywordBtn" | |
type="button" | |
> | |
Tambah | |
</button> | |
</div> | |
<div class="mt-2" id="keywordContainer"></div> | |
</div> | |
<div class="row justify-content-between"> | |
<div class="col-auto"> | |
<button | |
class="btn app-btn-secondary" | |
type="button" | |
id="bersihkanBtn" | |
> | |
Reset | |
</button> | |
</div> | |
<div class="col-auto"> | |
<button class="btn app-btn-primary" type="submit"> | |
Klasifikasi | |
</button> | |
</div> | |
</div> | |
</form> | |
</div> | |
<!--//app-card-body--> | |
</div> | |
<!--//app-card--> | |
</div> | |
</div> | |
<hr class="my-4" /> | |
<div class="row g-4 settings-section d-none" id="hasil"> | |
<div class="col-12"> | |
<h3 class="section-title">Hasil</h3> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div class="app-card app-card-stats-table h-100 shadow-sm"> | |
<div class="app-card-header p-3"> | |
<div class="row justify-content-between align-items-center"> | |
<div class="col-auto"> | |
<h4 class="app-card-title">Skor</h4> | |
</div> | |
</div> | |
<!--//row--> | |
</div> | |
<!--//app-card-header--> | |
<div class="app-card-body p-3 p-lg-4"> | |
<div class="table-responsive"> | |
<table class="table table-borderless mb-0"> | |
<thead> | |
<tr> | |
<th class="meta">Kelas</th> | |
<th class="meta stat-cell">Skor</th> | |
</tr> | |
</thead> | |
<tbody id="statsResult"></tbody> | |
</table> | |
</div> | |
<!--//table-responsive--> | |
</div> | |
<!--//app-card-body--> | |
</div> | |
<!--//app-card--> | |
</div> | |
<div class="col-12 col-lg-6"> | |
<div class="app-card app-card-chart h-100 shadow-sm"> | |
<div class="app-card-header p-3 border-0"> | |
<h4 class="app-card-title">Grafik</h4> | |
</div> | |
<div class="app-card-body pb-2"> | |
<div class="chart-container"> | |
<div class="chartjs-size-monitor"> | |
<div class="chartjs-size-monitor-expand"><div class=""></div></div> | |
<div class="chartjs-size-monitor-shrink"><div class=""></div></div> | |
</div> | |
<canvas | |
id="chart-doughnut" | |
style="display: block; width: 454px; height: 227px" | |
width="384" | |
height="157" | |
class="chartjs-render-monitor" | |
></canvas> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="col-12 mt-5 text-center"> | |
<h3 class="section-title"> | |
Dosen Kelompok Bidang Keahlian<br /><span | |
id="kbk" | |
style="color: #128c9b" | |
></span> | |
</h3> | |
</div> | |
<div class="row justify-content-center gy-2" id="lecturers"></div> | |
<div class="col-12 mt-5 text-center mb-3"> | |
<h3 class="section-title"> | |
Dosen dengan | |
<span style="color: #128c9b">Riwayat Bimbingan Termirip</span> | |
</h3> | |
</div> | |
<div class="container-xl" id="similarity-results"></div> | |
</div> | |
{% endblock content %} {% block script %} | |
<script> | |
let keywords = []; | |
$("#abstrak").on("input", function () { | |
let text = $(this).val().trim(); | |
let words = text.split(/\s+/).filter((word) => word.length > 0); | |
let wordCount = words.length; | |
if (wordCount >= 350) { | |
let trimmedWords = words.slice(0, 350); | |
$(this).val(trimmedWords.join(" ")); | |
wordCount = 350; | |
$("#wordCounter").css("color", "red"); | |
} else { | |
$("#wordCounter").css("color", "inherit"); | |
} | |
$("#wordCounter").text(`${wordCount}/350`); | |
}); | |
$("#addKeywordBtn").on("click", function (event) { | |
if (keywords.length == 5) { | |
alertMessage( | |
"Maksimal 5 kata kunci", | |
"Tidak dapat menambahkan kata kunci", | |
"info" | |
); | |
return; | |
} | |
let keyword = $("#keywordInput").val().trim(); | |
if (keyword) { | |
let badge = $( | |
`<span class="badge px-2 me-2" style="border: 1px solid #128c9b; color: #128c9b">${keyword}<svg class="close-badge ms-1" xmlns="http://www.w3.org/2000/svg" width="16" height="13" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16"> | |
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/> | |
</svg></span>` | |
); | |
$("#keywordContainer").append(badge); | |
keywords.push(keyword); | |
$("#keywordInput").val(""); | |
} | |
}); | |
$(document).on("click", ".close-badge", function () { | |
let removedKeyword = $(this).closest(".badge").text().trim(); | |
$(this).closest(".badge").remove(); | |
keywords = keywords.filter((word) => word !== removedKeyword); | |
}); | |
$("#bersihkanBtn").on("click", function () { | |
$("#abstrak").val(""); | |
$("#keywordInput").val(""); | |
$("#wordCounter").text("0/350").css("color", "inherit"); | |
$("#keywordContainer").empty(); | |
$("#hasil").addClass("d-none"); | |
keywords = []; | |
}); | |
$("#inference").on("submit", function (e) { | |
e.preventDefault(); | |
if ($("#abstrak").val().trim() == "") { | |
alertMessage( | |
"Abstrak Harus Diisi", | |
"Tidak dapat melakukan klasifikasi", | |
"error" | |
); | |
return; | |
} | |
if (keywords.length == 0) { | |
alertMessage( | |
"Minimal 1 Kata Kunci", | |
"Tidak dapat melakukan klasifikasi", | |
"error" | |
); | |
return; | |
} | |
$(".spinner").removeClass("d-none"); | |
$(".overlay").removeClass("d-none"); | |
$.ajax({ | |
type: "POST", | |
url: '{{ url_for("classifier.inference") }}', | |
contentType: "application/json", | |
data: JSON.stringify({ | |
abstrak: $("#abstrak").val(), | |
kata_kunci: keywords.join(", "), | |
}), | |
xhrFields: { | |
withCredentials: true, | |
}, | |
success: function (response) { | |
$("#statsResult").empty(); | |
probs = response["message"]["probs"]; | |
const classificationResult = Object.entries(probs) | |
.sort((x, y) => x[1] - y[1]) | |
.reverse(); | |
let isFirstRow = true; | |
classificationResult.forEach(([key, value]) => { | |
$("#statsResult").append( | |
`<tr> | |
<td>${key}</td> | |
<td class="stat-cell${ | |
isFirstRow ? " fw-bold" : "" | |
}" style="color: #128c9b">${value}%</td> | |
</tr>` | |
); | |
isFirstRow = false; | |
}); | |
var doughnutChart = $("#chart-doughnut")[0].getContext("2d"); | |
window.myDoughnut = new Chart( | |
doughnutChart, | |
initChart(Object.keys(probs), Object.values(probs)) | |
); | |
$("#kbk").text(response["message"]["kbk"]); | |
$("#lecturers").empty(); | |
$.each(response["message"]["lecturers"], function (index, lecturer) { | |
$("#lecturers").append( | |
`<div class="col-6 col-md-3"> | |
<div class="app-card app-card-doc shadow-sm h-100"> | |
<div class="app-card-thumb-holder p-3 d-flex justify-content-center"> | |
<div | |
style=" | |
width: 95px; | |
height: 95px; | |
overflow: hidden; | |
border-radius: 50%; | |
border: 2px solid white; | |
" | |
> | |
<img src="${lecturer.foto}" style="width: 100%; height: 100%; object-fit: cover" /> | |
</div> | |
</div> | |
<div class="app-card-body p-3 has-card-actions"> | |
<h4 class="app-doc-title truncate mb-0"> | |
<a href="#">${lecturer.nama}</a> | |
</h4> | |
<div class="app-doc-meta"> | |
<ul class="list-unstyled mb-0"> | |
<li> | |
Kelompok Bidang Keahlian: | |
<span class="text-unmuted">${lecturer.kelompok_bidang_keahlian}</span> | |
</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div>` | |
); | |
}); | |
$("#similarity-results").empty(); | |
var topSimilarity = response["message"]["top_similarity"]; | |
for (var index = 0; index < topSimilarity.length; index++) { | |
$("#similarity-results").append( | |
`<div class="app-card app-card-notification shadow-sm mb-4"> | |
<div class="app-card-header px-4 py-3"> | |
<div class="row g-3 align-items-center"> | |
<div class="col-12 col-lg-auto text-center text-lg-start"> | |
<div class="notification-type mb-3"> | |
<span class="badge" style="background-color: #128c9b" | |
>Rank #${topSimilarity[index]["rank"]}</span | |
> | |
</div> | |
<h4 class="notification-title mb-1">${ | |
topSimilarity[index]["supervisor"] | |
}</h4> | |
<ul class="notification-meta list-inline mb-0"> | |
<li class="list-inline-item fw-bold"> | |
Skor Kemiripan: <span style="color: #128c9b">${ | |
topSimilarity[index]["similarity_score"] | |
}%</span> | |
</li> | |
${ | |
topSimilarity[index]["similarity_score"] > 80 | |
? `<li class="fw-bold" style="color: red;">Tingkat Kemiripan Sangat Tinggi</li>` | |
: `` | |
} | |
</ul> | |
</div> | |
</div> | |
</div> | |
<div class="app-card-body p-4"> | |
<div class="notification-content mb-4"> | |
<b>Judul</b><br />${topSimilarity[index]["title"]} | |
</div> | |
<div class="notification-content mb-4"> | |
<b>Abstrak</b><br />${topSimilarity[index]["abstract"]} | |
</div> | |
<div class="notification-content"> | |
<b>Kata Kunci</b><br />${topSimilarity[index]["keywords"]} | |
</div> | |
</div> | |
<div class="app-card-footer px-4 py-3"> | |
<a class="action-link" href="${topSimilarity[index]["url"]}" | |
>${topSimilarity[index]["url"]}</a> | |
</div> | |
</div>` | |
); | |
} | |
$("#hasil").removeClass("d-none"); | |
$(".spinner").addClass("d-none"); | |
$(".overlay").addClass("d-none"); | |
$("html, body").animate( | |
{ | |
scrollTop: $("#hasil").offset().top - 50, | |
}, | |
1000 | |
); | |
}, | |
error: function (response) { | |
$(".spinner").addClass("d-none"); | |
$(".overlay").addClass("d-none"); | |
alertMessage("Klasifikasi Gagal", "Terjadi kesalahan server", "error"); | |
}, | |
}); | |
}); | |
</script> | |
{% endblock script %} | |