This commit is contained in:
everythingonblack
2025-06-10 16:28:40 +07:00
parent 984cd87bb4
commit 7847b02932
3 changed files with 147 additions and 163 deletions

View File

@@ -1,177 +1,157 @@
import React, { useState, useEffect } from 'react';
import styles from './ChatBot.module.css';
import React, { useState, useEffect } from 'react';
import styles from './ChatBot.module.css';
const ChatBot = ({ existingConversation, readOnly, hh }) => {
const [messages, setMessages] = useState([
{
sender: 'bot',
text: 'Halo 👋 Saya Klinik AI! Ada yang bisa saya bantu?',
time: getTime(),
quickReplies: [
'Bagaimana menghilangkan komedo',
'Apakah bisa menghilangkan bopeng?',
'Perutku mual dan kembung',
],
},
]);
const ChatBot = ({ existingConversation, readOnly, hh }) => {
const [messages, setMessages] = useState([
{
sender: 'bot',
text: 'Halo 👋 Saya Klinik AI! Ada yang bisa saya bantu?',
time: getTime(),
quickReplies: [
'Bagaimana menghilangkan komedo',
'Apakah bisa menghilangkan bopeng?',
'Perutku mual dan kembung',
],
},
]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (existingConversation && existingConversation.length > 0) {
setMessages(existingConversation);
}
}, [existingConversation])
useEffect(() => {
if (!localStorage.getItem('session')) {
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
if (existingConversation && existingConversation.length > 0) {
setMessages(existingConversation);
}
}, [existingConversation])
useEffect(() => {
if (!localStorage.getItem('session')) {
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
const sessionId = generateUUID();
const dateNow = new Date().toISOString();
const sessionId = generateUUID();
const dateNow = new Date().toISOString();
localStorage.setItem('session', JSON.stringify({ sessionId: sessionId, lastSeen: dateNow }))
}
}, []);
localStorage.setItem('session', JSON.stringify({ sessionId: sessionId, lastSeen: dateNow }))
}
}, []);
const sendMessage = async (textOverride = null) => {
const message = textOverride || input.trim();
if (message === '') return;
const sendMessage = async (textOverride = null) => {
const message = textOverride || input.trim();
if (message === '') return;
// Show user's message immediately
const newMessages = [
...messages,
{ sender: 'user', text: message, time: getTime() },
];
// Show user's message immediately
const newMessages = [
...messages,
{ sender: 'user', text: message, time: getTime() },
];
setMessages(newMessages);
setInput('');
setTimeout(() => setIsLoading(true), 1000);
setMessages(newMessages);
setInput('');
try {
// Send to backend
const response = await fetch('https://botdev.kediritechnopark.com/webhook/master-agent/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pertanyaan: message, sessionId: JSON.parse(localStorage.getItem('session')).sessionId, lastSeen: new Date().toISOString() }),
});
try {
// Send to backend
const response = await fetch('https://botdev.kediritechnopark.com/webhook/master-agent/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pertanyaan: message, sessionId: JSON.parse(localStorage.getItem('session')).sessionId, lastSeen: new Date().toISOString() }),
});
const data = await response.json();
console.log(data)
// Assuming your backend sends back something like: { answer: "text" }
// Adjust this according to your actual response shape
const botAnswer = data[0].output || data[0].output[0].text || 'Maaf, saya tidak mengerti.';
const data = await response.json();
console.log(data)
// Assuming your backend sends back something like: { answer: "text" }
// Adjust this according to your actual response shape
const botAnswer = data[0].output[0].text || data[0].output || 'Maaf, saya tidak mengerti.';
// Add bot's reply
setMessages(prev => [
...prev,
{ sender: 'bot', text: botAnswer, time: getTime() },
]);
// Add bot's reply
setMessages(prev => [
...prev,
{ sender: 'bot', text: botAnswer, time: getTime() },
]);
setIsLoading(false);
} catch (error) {
setMessages(prev => [
...prev,
{
sender: 'bot',
text: 'Maaf, terjadi kesalahan pada server. Silakan coba lagi nanti.',
time: getTime(),
},
]);
console.error('Fetch error:', error);
} finally {
setIsLoading(false);
}
setIsLoading(false);
setIsLoading(false);
} catch (error) {
setMessages(prev => [
...prev,
{
sender: 'bot',
text: 'Maaf, terjadi kesalahan pada server. Silakan coba lagi nanti.',
time: getTime(),
},
]);
console.error('Fetch error:', error);
} finally {
setIsLoading(false);
}
setIsLoading(false);
};
return (
<div className={styles.chatContainer} style={{ height: hh || '100vh' }}>
<div className={styles.chatHeader}>
<img src="/dermalounge.jpg" alt="Bot Avatar" />
<strong>DERMALOUNGE</strong>
</div>
<div className={styles.chatBody}>
{isLoading && (
<div className={`${styles.messageRow} ${styles.bot}`}>
<div className={`${styles.message} ${styles.bot}`}>
<em>Mengetik...</em>
</div>
</div>
)}
{messages.slice().reverse().map((msg, index) => (
<div
key={index}
className={`${styles.messageRow} ${styles[msg.sender]}`}
>
<div className={`${styles.message} ${styles[msg.sender]}`}>
{msg.text}
{msg.quickReplies && (
<div className={styles.quickReplies}>
{msg.quickReplies.map((reply, i) => (
<div
key={i}
className={styles.quickReply}
onClick={() => sendMessage(reply)}
>
{reply}
</div>
))}
</div>
)}
<div className={styles.timestamp}>{msg.time}</div>
</div>
</div>
))}
</div>
<div className={styles.chatInput} style={{ visibility: readOnly ? 'hidden' : 'visible', marginTop: readOnly ? '-59px' : '0px' }}>
<input
type="text"
placeholder="Ketik pesan..."
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
disabled={isLoading}
/>
<button onClick={() => sendMessage()} disabled={isLoading}>
Kirim
</button>
</div>
</div>
);
};
return (
<div className={styles.chatContainer} style={{ height: hh || '100vh' }}>
<div className={styles.chatHeader}>
<img src="https://i.ibb.co/YXxXr72/bot-avatar.png" alt="Bot Avatar" />
<strong>Kloowear AI Assistant</strong>
</div>
function getTime() {
const now = new Date();
return now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
<div className={styles.chatBody}>
{isLoading && (
<div className={`${styles.messageRow} ${styles.bot}`}>
<img
src="https://i.ibb.co/YXxXr72/bot-avatar.png"
alt="Bot"
className={styles.avatar}
/>
<div className={`${styles.message} ${styles.bot}`}>
<em>Mengetik...</em>
</div>
</div>
)}
{messages.slice().reverse().map((msg, index) => (
<div
key={index}
className={`${styles.messageRow} ${styles[msg.sender]}`}
>
{msg.sender === 'bot' && (
<img
src="https://i.ibb.co/YXxXr72/bot-avatar.png"
alt="Bot"
className={styles.avatar}
/>
)}
<div className={`${styles.message} ${styles[msg.sender]}`}>
{msg.text}
{msg.quickReplies && (
<div className={styles.quickReplies}>
{msg.quickReplies.map((reply, i) => (
<div
key={i}
className={styles.quickReply}
onClick={() => sendMessage(reply)}
>
{reply}
</div>
))}
</div>
)}
<div className={styles.timestamp}>{msg.time}</div>
</div>
{msg.sender === 'user' && (
<img
src="https://i.ibb.co/4pDNDk1/user-avatar.png"
alt="User"
className={styles.avatar}
/>
)}
</div>
))}
</div>
<div className={styles.chatInput} style={{ visibility: readOnly ? 'hidden' : 'visible', marginTop: readOnly ? '-59px' : '0px' }}>
<input
type="text"
placeholder="Ketik pesan..."
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
disabled={isLoading}
/>
<button onClick={() => sendMessage()} disabled={isLoading}>
Kirim
</button>
</div>
</div>
);
};
function getTime() {
const now = new Date();
return now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
export default ChatBot;
export default ChatBot;

View File

@@ -128,9 +128,9 @@ const Dashboard = () => {
return (
<div className={styles.dashboardContainer}>
<div className={styles.dashboardHeader}>
<img src="https://i.ibb.co/YXxXr72/bot-avatar.png" alt="Bot Avatar" />
<img src="/dermalounge.jpg" alt="Bot Avatar" />
<div>
<h1>Kloowear AI Admin Dashboard</h1>
<h1>Dermalounge AI Admin Dashboard</h1>
<p>Statistik penggunaan chatbot secara real-time</p>
</div>
</div>
@@ -159,6 +159,10 @@ const Dashboard = () => {
<canvas ref={chartRef}></canvas>
</div>
<div className={styles.footer}>
UNTUK MENAMBAHKAN LAYANAN, KUNJUNGI <a href="https://drive.kediritechnopark.com">LINK INI</a>
dengan username: dermalounge, password: 1234
</div>
<div className={styles.footer}>
&copy; 2025 Kloowear AI - Admin Panel
</div>