feature: chatbot pimpinan
This commit is contained in:
@@ -88,9 +88,42 @@ class ChatbotController extends Controller
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Panggil service untuk generate text
|
// Panggil service untuk generate text
|
||||||
$response = $this->openAIService->mainGenerateText($request->input('prompt'));
|
$classifyResponse = $this->openAIService->classifyMainGenerateText($request->input('prompt'));
|
||||||
|
info($classifyResponse);
|
||||||
|
|
||||||
|
// Pastikan hasil klasifikasi valid sebelum melanjutkan
|
||||||
|
$validCategories = [
|
||||||
|
'reklame', 'business_or_industries', 'customers',
|
||||||
|
'pbg', 'retribusi', 'spatial_plannings',
|
||||||
|
'tourisms', 'umkms'
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!in_array($classifyResponse, $validCategories)) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => ''
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$queryResponse = $this->openAIService->createMainQuery($classifyResponse, $request->input('prompt'));
|
||||||
|
info($queryResponse);
|
||||||
|
|
||||||
|
$firstValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
|
||||||
|
$secondValidation = $this->openAIService->validateSyntaxQuery($queryResponse);
|
||||||
|
|
||||||
|
$formattedResultQuery = "[]";
|
||||||
|
|
||||||
return response()->json(['response' => $response]);
|
if($firstValidation === "VALID" && $secondValidation === "VALID")
|
||||||
|
{
|
||||||
|
$queryResponse = str_replace(['```sql', '```'], '', $queryResponse);
|
||||||
|
$queryResult = DB::select($queryResponse);
|
||||||
|
info($queryResult);
|
||||||
|
$formattedResultQuery = json_encode($queryResult, JSON_PRETTY_PRINT);
|
||||||
|
info($formattedResultQuery);
|
||||||
|
}
|
||||||
|
$nlpResult = $this->openAIService->generateNLPFromQuery($request->input('prompt'), $formattedResultQuery);
|
||||||
|
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
|
||||||
|
|
||||||
|
return response()->json(['response' => $finalGeneratedText]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// Tangani error dan log exception
|
// Tangani error dan log exception
|
||||||
\Log::error("Error generating text: " . $e->getMessage());
|
\Log::error("Error generating text: " . $e->getMessage());
|
||||||
|
|||||||
@@ -153,6 +153,72 @@ class OpenAIService
|
|||||||
|
|
||||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function classifyMainGenerateText($prompt) {
|
||||||
|
$response = $this->client->chat()->create([
|
||||||
|
'model' => 'gpt-4o-mini',
|
||||||
|
'messages' => [
|
||||||
|
[
|
||||||
|
'role' => 'system',
|
||||||
|
'content' => "You are an assistant that classifies text into one of the following categories:
|
||||||
|
- reklame (ads or product/service promotions)
|
||||||
|
- business_or_industries (business or industries in general)
|
||||||
|
- customers (customers, consumers, or service users)
|
||||||
|
- pbg (tasks related to Building Approval)
|
||||||
|
- retribusi (retributions related to PBG)
|
||||||
|
- spatial_plannings (spatial planning)
|
||||||
|
- tourisms (tourism and tourist destinations)
|
||||||
|
- umkms (Micro, Small, and Medium Enterprises)
|
||||||
|
|
||||||
|
Respond with only one of the categories above without any additional explanation."
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'role' => 'user',
|
||||||
|
'content' => "Classify the following text:\n\n" . $prompt
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createMainQuery($classify, $prompt)
|
||||||
|
{
|
||||||
|
// Load file JSON
|
||||||
|
$jsonPath = public_path('templates/table_config.json');
|
||||||
|
$jsonConfig = json_decode(file_get_contents($jsonPath), true);
|
||||||
|
|
||||||
|
// Pastikan kategori tersedia dalam konfigurasi
|
||||||
|
if (!isset($jsonConfig[$classify])) {
|
||||||
|
return "Error: Kategori tidak ditemukan dalam konfigurasi.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambil nama tabel dan kolom
|
||||||
|
$tableName = $jsonConfig[$classify]['table_name'];
|
||||||
|
$columns = implode(', ', $jsonConfig[$classify]['list_column']);
|
||||||
|
|
||||||
|
$response = $this->client->chat()->create([
|
||||||
|
'model' => 'gpt-4o-mini',
|
||||||
|
'messages' => [
|
||||||
|
[
|
||||||
|
'role' => 'system',
|
||||||
|
'content' => "You are an AI assistant that generates only valid MariaDB queries based on user requests.
|
||||||
|
Use the following table information to construct the SQL query:
|
||||||
|
|
||||||
|
- Table Name: $tableName
|
||||||
|
- Available Columns: $columns
|
||||||
|
|
||||||
|
Generate only the SQL query without any explanation or additional text."
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'role' => 'user',
|
||||||
|
'content' => $prompt
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||||
|
}
|
||||||
|
|
||||||
public function mainGenerateText($prompt) {
|
public function mainGenerateText($prompt) {
|
||||||
$response = $this->client->chat()->create([
|
$response = $this->client->chat()->create([
|
||||||
|
|||||||
@@ -1,145 +1,169 @@
|
|||||||
{
|
{
|
||||||
"v_advertisements": [
|
"reklame": {
|
||||||
"no",
|
"table_name": "v_advertisements",
|
||||||
"business_name",
|
"list_column": [
|
||||||
"npwpd",
|
"no",
|
||||||
"advertisement_type",
|
"business_name",
|
||||||
"advertisement_content",
|
"npwpd",
|
||||||
"business_address",
|
"advertisement_type",
|
||||||
"advertisement_location",
|
"advertisement_content",
|
||||||
"village_name",
|
"business_address",
|
||||||
"district_name",
|
"advertisement_location",
|
||||||
"length",
|
"village_name",
|
||||||
"width",
|
"district_name",
|
||||||
"viewing_angle",
|
"length",
|
||||||
"face",
|
"width",
|
||||||
"area",
|
"viewing_angle",
|
||||||
"angle",
|
"face",
|
||||||
"contact"
|
"area",
|
||||||
],
|
"angle",
|
||||||
"business_or_industries": [
|
"contact"
|
||||||
"nama_kecamatan",
|
]
|
||||||
"nama_kelurahan",
|
},
|
||||||
"nop",
|
"business_or_industries": {
|
||||||
"nama_wajib_pajak",
|
"table_name": "business_or_industries",
|
||||||
"alamat_wajib_pajak",
|
"list_column": [
|
||||||
"alamat_objek_pajak",
|
"nama_kecamatan",
|
||||||
"luas_bumi",
|
"nama_kelurahan",
|
||||||
"luas_bangunan",
|
"nop",
|
||||||
"njop_bumi",
|
"nama_wajib_pajak",
|
||||||
"njop_bangunan",
|
"alamat_wajib_pajak",
|
||||||
"ketetapan",
|
"alamat_objek_pajak",
|
||||||
"tahun_pajak",
|
"luas_bumi",
|
||||||
"created_at",
|
"luas_bangunan",
|
||||||
"updated_at"
|
"njop_bumi",
|
||||||
],
|
"njop_bangunan",
|
||||||
"customers": [
|
"ketetapan",
|
||||||
"nomor_pelanggan",
|
"tahun_pajak",
|
||||||
"kota_pelayanan",
|
"created_at",
|
||||||
"nama",
|
"updated_at"
|
||||||
"alamat",
|
]
|
||||||
"latitude",
|
},
|
||||||
"longitude",
|
"customers": {
|
||||||
"created_at",
|
"table_name": "customers",
|
||||||
"updated_at"
|
"list_column": [
|
||||||
],
|
"nomor_pelanggan",
|
||||||
"pbg_task": [
|
"kota_pelayanan",
|
||||||
"uuid",
|
"nama",
|
||||||
"name",
|
"alamat",
|
||||||
"owner_name",
|
"latitude",
|
||||||
"application_type",
|
"longitude",
|
||||||
"application_type_name",
|
"created_at",
|
||||||
"condition",
|
"updated_at"
|
||||||
"registration_number",
|
]
|
||||||
"document_number",
|
},
|
||||||
"address",
|
"pbg": {
|
||||||
"status_name",
|
"table_name": "pbg_task",
|
||||||
"slf_status_name",
|
"list_column": [
|
||||||
"function_type",
|
"uuid",
|
||||||
"consultation_type",
|
"name",
|
||||||
"due_date",
|
"owner_name",
|
||||||
"land_certificate_phase",
|
"application_type",
|
||||||
"created_at",
|
"application_type_name",
|
||||||
"updated_at",
|
"condition",
|
||||||
"task_created_at"
|
"registration_number",
|
||||||
],
|
"document_number",
|
||||||
"v_pbg_task_retributions": [
|
"address",
|
||||||
"uuid",
|
"status_name",
|
||||||
"name",
|
"slf_status_name",
|
||||||
"owner_name",
|
"function_type",
|
||||||
"application_type",
|
"consultation_type",
|
||||||
"application_type_name",
|
"due_date",
|
||||||
"condition",
|
"land_certificate_phase",
|
||||||
"registration_number",
|
"created_at",
|
||||||
"document_number",
|
"updated_at",
|
||||||
"address",
|
"task_created_at"
|
||||||
"status_name",
|
]
|
||||||
"slf_status_name",
|
},
|
||||||
"consultation_type",
|
"retribusi": {
|
||||||
"due_date",
|
"table_name": "v_pbg_task_with_retributions",
|
||||||
"land_certificate_phase",
|
"list_column": [
|
||||||
"created_at",
|
"uuid",
|
||||||
"updated_at",
|
"name",
|
||||||
"task_created_at",
|
"owner_name",
|
||||||
"nilai_retribusi_bangunan"
|
"application_type",
|
||||||
],
|
"application_type_name",
|
||||||
"spatial_plannings": [
|
"condition",
|
||||||
"created_at",
|
"registration_number",
|
||||||
"updated_at",
|
"document_number",
|
||||||
"name",
|
"address",
|
||||||
"kbli",
|
"status_name",
|
||||||
"activities",
|
"slf_status_name",
|
||||||
"area",
|
"consultation_type",
|
||||||
"location",
|
"due_date",
|
||||||
"number",
|
"land_certificate_phase",
|
||||||
"date"
|
"created_at",
|
||||||
],
|
"updated_at",
|
||||||
"v_tourisms": [
|
"task_created_at",
|
||||||
"project_id",
|
"nilai_retribusi_bangunan"
|
||||||
"project_type_id",
|
]
|
||||||
"nib",
|
},
|
||||||
"business_name",
|
"spatial_plannings": {
|
||||||
"oss_publication_date",
|
"table_name": "spatial_plannings",
|
||||||
"investment_status_description",
|
"list_column": [
|
||||||
"business_form",
|
"created_at",
|
||||||
"project_risk",
|
"updated_at",
|
||||||
"project_name",
|
"name",
|
||||||
"business_scale",
|
"kbli",
|
||||||
"business_address",
|
"activities",
|
||||||
"village_name",
|
"area",
|
||||||
"district_name",
|
"location",
|
||||||
"longitude",
|
"number",
|
||||||
"latitude",
|
"date"
|
||||||
"project_submission_date",
|
]
|
||||||
"kbli_title",
|
},
|
||||||
"supervisory_sector",
|
"tourisms": {
|
||||||
"user_name",
|
"table_name": "v_tourisms",
|
||||||
"email",
|
"list_column": [
|
||||||
"contact",
|
"project_id",
|
||||||
"land_area_in_m2",
|
"project_type_id",
|
||||||
"investment_amount",
|
"nib",
|
||||||
"tki"
|
"business_name",
|
||||||
],
|
"oss_publication_date",
|
||||||
"v_umkms": [
|
"investment_status_description",
|
||||||
"business_address",
|
"business_form",
|
||||||
"business_contact",
|
"project_risk",
|
||||||
"business_desc",
|
"project_name",
|
||||||
"business_form",
|
"business_scale",
|
||||||
"business_id_number",
|
"business_address",
|
||||||
"",
|
"village_name",
|
||||||
"",
|
"district_name",
|
||||||
"",
|
"longitude",
|
||||||
"",
|
"latitude",
|
||||||
"",
|
"project_submission_date",
|
||||||
"",
|
"kbli_title",
|
||||||
"",
|
"supervisory_sector",
|
||||||
"",
|
"user_name",
|
||||||
"",
|
"email",
|
||||||
"",
|
"contact",
|
||||||
"",
|
"land_area_in_m2",
|
||||||
"",
|
"investment_amount",
|
||||||
"",
|
"tki"
|
||||||
"",
|
]
|
||||||
""
|
},
|
||||||
]
|
"umkms": {
|
||||||
|
"table_name": "v_umkms",
|
||||||
|
"list_column": [
|
||||||
|
"business_address",
|
||||||
|
"business_contact",
|
||||||
|
"business_desc",
|
||||||
|
"business_form",
|
||||||
|
"business_id_number",
|
||||||
|
"business_name",
|
||||||
|
"business_scale",
|
||||||
|
"business_type",
|
||||||
|
"created_at",
|
||||||
|
"district_name",
|
||||||
|
"land_area",
|
||||||
|
"number_of_employee",
|
||||||
|
"owner_address",
|
||||||
|
"owner_contact",
|
||||||
|
"owner_id",
|
||||||
|
"owner_name",
|
||||||
|
"permit_status",
|
||||||
|
"revenue",
|
||||||
|
"updated_at",
|
||||||
|
"village_name"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
import GlobalConfig from "../global-config.js";
|
import GlobalConfig from "../global-config.js";
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const timeElements = document.querySelectorAll(".sending-message-time p");
|
||||||
|
|
||||||
|
timeElements.forEach((element) => {
|
||||||
|
element.textContent = getCurrentTime();
|
||||||
|
});
|
||||||
|
|
||||||
const textarea = document.getElementById("user-message");
|
const textarea = document.getElementById("user-message");
|
||||||
const sendButton = document.getElementById("send");
|
const sendButton = document.getElementById("send");
|
||||||
const conversationArea = document.querySelector(".row.flex-grow");
|
const conversationArea = document.querySelector(".row.flex-grow");
|
||||||
@@ -16,13 +22,20 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
addMessage(userText, "user");
|
addMessage(userText, "user");
|
||||||
|
|
||||||
// Tambahkan pesan bot sementara dengan "Loading..."
|
// Tambahkan pesan bot sementara dengan "Loading..."
|
||||||
const botMessageElement = addMessage('<div class="loader w-auto"></div>', "bot");
|
const botMessageElement = addMessage('<div class="bot-message-text">...</div>', "bot");
|
||||||
|
|
||||||
// Panggil API untuk mendapatkan response dari bot
|
const messageTextContainer = botMessageElement.querySelector(".bot-message-text");
|
||||||
|
if (messageTextContainer) {
|
||||||
|
messageTextContainer.innerHTML = '<div class="loader ms-3"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panggil API untuk mendapatkan respons dari bot
|
||||||
const botResponse = await getBotResponse(userText);
|
const botResponse = await getBotResponse(userText);
|
||||||
|
|
||||||
// Perbarui pesan bot dengan respons yang sebenarnya
|
// Perbarui pesan bot dengan respons yang sebenarnya
|
||||||
botMessageElement.innerHTML = botResponse;;
|
if (messageTextContainer) {
|
||||||
|
messageTextContainer.innerHTML = botResponse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,54 +50,78 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getCurrentTime() {
|
||||||
|
const now = new Date();
|
||||||
|
return now.getHours().toString().padStart(2, "0") + ":" + now.getMinutes().toString().padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
function addMessage(text, sender) {
|
function addMessage(text, sender) {
|
||||||
const messageRow = document.createElement("div");
|
const messageRow = document.createElement("div");
|
||||||
messageRow.classList.add("row", "flex-grow", "overflow-auto");
|
// Atur posisi berdasarkan sender (user -> end, bot -> start)
|
||||||
|
messageRow.classList.add("row", "flex-grow", "overflow-auto", sender === "user" ? "justify-content-end" : "justify-content-start");
|
||||||
|
|
||||||
const messageCol = document.createElement("div");
|
const messageCol = document.createElement("div");
|
||||||
messageCol.classList.add("w-auto", "d-inline-block"); // Menyesuaikan lebar konten
|
messageCol.classList.add("col-9", "w-auto");
|
||||||
|
|
||||||
|
// Atur lebar maksimum berdasarkan sender
|
||||||
|
messageCol.style.maxWidth = sender === "user" ? "50%" : "75%";
|
||||||
|
|
||||||
|
// Container untuk menyimpan nama dan bubble chat
|
||||||
|
const messageWrapper = document.createElement("div");
|
||||||
|
messageWrapper.classList.add("d-flex", "flex-column");
|
||||||
|
|
||||||
|
// Tambahkan Nama di luar bubble chat
|
||||||
|
const messageName = document.createElement("p");
|
||||||
|
messageName.classList.add("fw-bolder", sender === "user" ? "text-end" : "text-start", "mb-1");
|
||||||
|
messageName.textContent = sender === "user" ? "You" : "Neng Bedas";
|
||||||
|
|
||||||
|
// Bubble Chat
|
||||||
|
const messageContainer = document.createElement("div");
|
||||||
|
messageContainer.classList.add("p-2", "rounded", "mb-2", "d-inline-block");
|
||||||
if (sender === "user") {
|
if (sender === "user") {
|
||||||
messageCol.classList.add("ms-auto", "max-w-50"); // Rata kanan, max 50% (setara col-6)
|
messageContainer.classList.add("user-response", "bg-primary", "text-white");
|
||||||
} else {
|
} else {
|
||||||
messageCol.classList.add("max-w-75"); // Max 75% (setara col-9)
|
messageContainer.classList.add("bot-response", "bg-light");
|
||||||
|
}
|
||||||
|
|
||||||
// Tambahkan avatar hanya untuk bot
|
const messageContent = document.createElement("div");
|
||||||
const avatarSpan = document.createElement("span");
|
messageContent.classList.add("bot-message-text", "mb-0", "text-start");
|
||||||
avatarSpan.classList.add("d-flex", "align-items-center", "mb-1");
|
messageContent.textContent = text;
|
||||||
|
|
||||||
|
// Waktu di dalam bubble chat
|
||||||
|
const messageTime = document.createElement("div");
|
||||||
|
messageTime.classList.add("sending-message-time", "text-end", "mt-1");
|
||||||
|
messageTime.innerHTML = `<p class="small mb-0 ${sender === "user" ? "text-white text-start" : "text-muted"}">${getCurrentTime()}</p>`;
|
||||||
|
|
||||||
|
messageContainer.appendChild(messageContent);
|
||||||
|
messageContainer.appendChild(messageTime);
|
||||||
|
|
||||||
|
// Jika pengirim adalah bot, tambahkan avatar
|
||||||
|
if (sender !== "user") {
|
||||||
|
const avatarContainer = document.createElement("div");
|
||||||
|
avatarContainer.classList.add("col-auto", "pe-0");
|
||||||
|
|
||||||
const avatarImg = document.createElement("img");
|
const avatarImg = document.createElement("img");
|
||||||
avatarImg.classList.add("rounded-circle");
|
avatarImg.classList.add("rounded-circle");
|
||||||
avatarImg.width = 32;
|
avatarImg.width = 45;
|
||||||
avatarImg.src = "/images/iconchatbot.jpeg";
|
avatarImg.src = "/images/iconchatbot.jpeg";
|
||||||
avatarImg.alt = "bot-avatar";
|
avatarImg.alt = "bot-avatar";
|
||||||
|
|
||||||
avatarSpan.appendChild(avatarImg);
|
avatarContainer.appendChild(avatarImg);
|
||||||
messageCol.appendChild(avatarSpan);
|
messageRow.appendChild(avatarContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageDiv = document.createElement("div");
|
// Masukkan nama dan bubble ke dalam wrapper
|
||||||
messageDiv.classList.add("p-2", "rounded", "mb-2");
|
messageWrapper.appendChild(messageName);
|
||||||
|
messageWrapper.appendChild(messageContainer);
|
||||||
if (sender === "user") {
|
messageCol.appendChild(messageWrapper);
|
||||||
messageDiv.classList.add("user-response", "bg-primary", "text-white");
|
|
||||||
} else {
|
|
||||||
messageDiv.classList.add("bot-response", "bg-light");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Menyisipkan konten HTML langsung (bisa berupa teks atau loader)
|
|
||||||
messageDiv.innerHTML = text;
|
|
||||||
messageCol.appendChild(messageDiv);
|
|
||||||
messageRow.appendChild(messageCol);
|
messageRow.appendChild(messageCol);
|
||||||
|
|
||||||
// Tambahkan ke area percakapan
|
|
||||||
conversationArea.appendChild(messageRow);
|
conversationArea.appendChild(messageRow);
|
||||||
|
|
||||||
// Scroll otomatis ke bawah
|
|
||||||
conversationArea.scrollTop = conversationArea.scrollHeight;
|
conversationArea.scrollTop = conversationArea.scrollHeight;
|
||||||
|
|
||||||
return messageDiv; // Mengembalikan elemen agar bisa diperbarui nanti
|
return messageContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fungsi untuk memanggil API
|
// Fungsi untuk memanggil API
|
||||||
async function getBotResponse(userText) {
|
async function getBotResponse(userText) {
|
||||||
|
|||||||
@@ -86,64 +86,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const now = new Date();
|
const now = new Date();
|
||||||
return now.getHours().toString().padStart(2, "0") + ":" + now.getMinutes().toString().padStart(2, "0");
|
return now.getHours().toString().padStart(2, "0") + ":" + now.getMinutes().toString().padStart(2, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// function addMessage(text, sender) {
|
|
||||||
// const messageRow = document.createElement("div");
|
|
||||||
// // Atur posisi berdasarkan sender (user -> end, bot -> start)
|
|
||||||
// messageRow.classList.add("row", "flex-grow", "overflow-auto", sender === "user" ? "justify-content-end" : "justify-content-start");
|
|
||||||
|
|
||||||
// const messageCol = document.createElement("div");
|
|
||||||
// messageCol.classList.add("col-9", "w-auto");
|
|
||||||
|
|
||||||
// // Atur lebar maksimum berdasarkan sender
|
|
||||||
// messageCol.style.maxWidth = sender === "user" ? "50%" : "75%";
|
|
||||||
|
|
||||||
// const messageContainer = document.createElement("div");
|
|
||||||
// messageContainer.classList.add("p-2", "rounded", "mb-2", "d-flex", "align-items-center");
|
|
||||||
|
|
||||||
// if (sender === "user") {
|
|
||||||
// messageContainer.classList.add("user-response", "bg-primary", "text-white", "ms-auto");
|
|
||||||
// } else {
|
|
||||||
// messageContainer.classList.add("bot-response", "bg-light");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (sender !== "user") {
|
|
||||||
// const avatarSpan = document.createElement("span");
|
|
||||||
// avatarSpan.classList.add("d-flex", "align-self-start", "mb-1");
|
|
||||||
|
|
||||||
// const avatarImg = document.createElement("img");
|
|
||||||
// avatarImg.classList.add("rounded-circle");
|
|
||||||
// avatarImg.width = 45;
|
|
||||||
// avatarImg.src = "/images/iconchatbot.jpeg";
|
|
||||||
// avatarImg.alt = "bot-avatar";
|
|
||||||
|
|
||||||
// avatarSpan.appendChild(avatarImg);
|
|
||||||
// messageContainer.appendChild(avatarSpan);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const messageContentWrapper = document.createElement("div");
|
|
||||||
// messageContentWrapper.classList.add("d-flex", "flex-column", "ms-2");
|
|
||||||
|
|
||||||
// const messageContent = document.createElement("div");
|
|
||||||
// messageContent.classList.add("row");
|
|
||||||
// messageContent.innerHTML = `<p class="fw-bolder ${sender === "user" ? "text-start" : "text-start"} mb-1">${sender === "user" ? "You" : "Neng Bedas"}</p><div class="bot-message-text mb-0 text-start">${text}</div>`;
|
|
||||||
|
|
||||||
// const messageTime = document.createElement("div");
|
|
||||||
// messageTime.classList.add("sending-message-time");
|
|
||||||
// messageTime.innerHTML = `<p class="small mb-0 ${sender === "user" ? "text-end text-white" : "text-end text-muted"}">${getCurrentTime()}</p>`;
|
|
||||||
|
|
||||||
|
|
||||||
// messageContentWrapper.appendChild(messageContent);
|
|
||||||
// messageContentWrapper.appendChild(messageTime);
|
|
||||||
// messageContainer.appendChild(messageContentWrapper);
|
|
||||||
// messageCol.appendChild(messageContainer);
|
|
||||||
// messageRow.appendChild(messageCol);
|
|
||||||
|
|
||||||
// conversationArea.appendChild(messageRow);
|
|
||||||
// conversationArea.scrollTop = conversationArea.scrollHeight;
|
|
||||||
|
|
||||||
// return messageContainer;
|
|
||||||
// }
|
|
||||||
|
|
||||||
function addMessage(text, sender) {
|
function addMessage(text, sender) {
|
||||||
const messageRow = document.createElement("div");
|
const messageRow = document.createElement("div");
|
||||||
|
|||||||
@@ -32,33 +32,41 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body d-flex flex-column" style="height: 700px;">
|
<div class="card-body d-flex flex-column" style="height: 700px;">
|
||||||
<!-- Conversation Area -->
|
<!-- Conversation Area -->
|
||||||
|
|
||||||
<!-- Bot Response -->
|
<!-- Bot Response -->
|
||||||
<div class="row flex-grow overflow-auto">
|
<div class="row flex-grow overflow-auto align-items-start">
|
||||||
|
<!-- Avatar -->
|
||||||
|
<div class="col-auto alignpe-0">
|
||||||
|
<img class="rounded-circle" width="45" src="/images/iconchatbot.jpeg" alt="avatar-3">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Nama dan Bubble Chat -->
|
||||||
<div class="col-9 w-auto">
|
<div class="col-9 w-auto">
|
||||||
<span class="d-flex align-items-center mb-1">
|
<!-- Nama Bot -->
|
||||||
<img class="rounded-circle" width="32" src="/images/iconchatbot.jpeg" alt="avatar-3">
|
<p class="fw-bolder mb-1">Neng Bedas</p>
|
||||||
</span>
|
|
||||||
<div class="bot-response p-2 bg-light rounded mb-2">
|
<!-- Bubble Chat -->
|
||||||
<p>Halo! Ada yang bisa saya bantu?</p>
|
<div class="bot-response p-2 bg-light rounded mb-2 d-inline-block">
|
||||||
|
<p class="mb-0">Halo! Ada yang bisa saya bantu?</p>
|
||||||
|
|
||||||
|
<!-- Waktu (Tetap di Dalam Bubble Chat) -->
|
||||||
|
<div class="sending-message-time text-end mt-1">
|
||||||
|
<p class="text-muted small mb-0">Now</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Input & Button (Selalu di Bawah) -->
|
<!-- Input & Button (Selalu di Bawah) -->
|
||||||
<div class="row mt-auto">
|
<div class="row mt-auto">
|
||||||
<div class="col-xl-12 d-flex align-items-end gap-1">
|
<div class="col-xl-12 d-flex align-items-end gap-1">
|
||||||
<textarea class="form-control" id="user-message"></textarea>
|
<textarea class="form-control" id="user-message"></textarea>
|
||||||
<button id="send" class="btn btn-primary btn-lg rounded-pill">
|
<button id="send" class="btn btn-primary btn-lg h-100 d-flex align-items-center">
|
||||||
<i class='bx bx-send'></i>
|
<i class='bx bx-send'></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{{-- <div class="col-xl-2 d-flex justify-content-end">
|
|
||||||
|
|
||||||
</div> --}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -55,26 +55,6 @@
|
|||||||
<div class="card-body d-flex flex-column" style="height: 700px;">
|
<div class="card-body d-flex flex-column" style="height: 700px;">
|
||||||
<!-- Conversation Area -->
|
<!-- Conversation Area -->
|
||||||
|
|
||||||
{{-- <!-- Bot Response -->
|
|
||||||
<div class="row flex-grow overflow-auto">
|
|
||||||
<div class="col-9 w-auto">
|
|
||||||
<div class="bot-response p-2 bg-light rounded mb-2 d-flex align-items-center">
|
|
||||||
<span class="d-flex align-items-center mb-1">
|
|
||||||
<img class="rounded-circle" width="45" src="/images/iconchatbot.jpeg" alt="avatar-3">
|
|
||||||
</span>
|
|
||||||
<div class="d-flex flex-column ms-2">
|
|
||||||
<div class="row">
|
|
||||||
<p class="fw-bolder mb-1">Neng Bedas</p>
|
|
||||||
<p class="mb-0">Halo! Ada yang bisa saya bantu?</p>
|
|
||||||
</div>
|
|
||||||
<div class="sending-message-time">
|
|
||||||
<p class="text-muted small mb-0 text-end">Now</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> --}}
|
|
||||||
|
|
||||||
<!-- Bot Response -->
|
<!-- Bot Response -->
|
||||||
<div class="row flex-grow overflow-auto align-items-start">
|
<div class="row flex-grow overflow-auto align-items-start">
|
||||||
<!-- Avatar -->
|
<!-- Avatar -->
|
||||||
|
|||||||
Reference in New Issue
Block a user