Files
EduCatWeb/views/chat.ejs
2025-07-06 23:39:32 +08:00

257 lines
11 KiB
Plaintext

<%- include('partials/header') %>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-lg border-0 chat">
<div class="card-header bg-primary text-white">
<div class="d-flex justify-content-between align-items-center">
<h3 class="mb-0"><i class="fas fa-comments me-2"></i>Chat with EduCat AI</h3>
<button type="button" id="clear-chat-btn" class="btn btn-outline-light btn-sm" title="Clear Chat History">
<i class="fas fa-trash-alt me-1"></i>Clear
</button>
</div>
</div>
<div class="card-body p-0">
<div id="chat-container" class="p-4" style="height: 500px; overflow-y: auto;">
<!-- Initial bot message will be added here if no history exists -->
</div>
<div class="border-top bg-light p-3">
<div class="input-group">
<input type="text" id="chat-input" class="form-control border-0 bg-white shadow-sm" placeholder="Type your message here..." style="border-radius: 25px 0 0 25px; padding: 12px 20px;">
<button type="button" id="send-btn" class="btn btn-primary px-4 border-0" style="border-radius: 0 25px 25px 0;">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-6">
<div class="card border-0 shadow-sm">
<div class="card-body text-center">
<i class="fas fa-question-circle fa-2x text-primary mb-3"></i>
<h6>Ask Questions</h6>
<p class="text-muted small">Get answers about your study materials</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card border-0 shadow-sm">
<div class="card-body text-center">
<i class="fas fa-graduation-cap fa-2x text-success mb-3"></i>
<h6>Study Help</h6>
<p class="text-muted small">Get study tips and techniques</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Get chat history from server-side rendered data
const serverChatHistory = <%- JSON.stringify(chatHistory || []) %>;
document.addEventListener('DOMContentLoaded', function() {
const chatContainer = document.getElementById('chat-container');
const chatInput = document.getElementById('chat-input');
const sendBtn = document.getElementById('send-btn');
const clearChatBtn = document.getElementById('clear-chat-btn');
// Load existing chat history from server
loadChatHistory();
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
clearChatBtn.addEventListener('click', clearChatHistory);
function loadChatHistory() {
// Clear the container first
chatContainer.innerHTML = '';
if (serverChatHistory.length === 0) {
// Show initial welcome message if no history exists
addWelcomeMessage();
} else {
// Load all previous messages
serverChatHistory.forEach(conversation => {
addMessageToChat('user', conversation.human, false);
addMessageToChat('bot', conversation.ai, false);
});
}
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function addWelcomeMessage() {
const messageDiv = document.createElement('div');
messageDiv.className = 'chat-message bot-message mb-3';
messageDiv.innerHTML = `
<div class="d-flex align-items-start">
<div class="avatar bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3 flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
<i class="fas fa-cat" style="font-size: 1.2rem;"></i>
</div>
<div class="message-content flex-grow-1">
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
<p class="mb-0">Hello! I'm EduCat AI, your study assistant. I can help you with questions about your notes, study techniques, and academic topics. How can I assist you today?</p>
</div>
<small class="text-muted d-block mt-1">Just now</small>
</div>
</div>
`;
chatContainer.appendChild(messageDiv);
}
function sendMessage() {
const message = chatInput.value.trim();
if (!message) return;
// Add user message to chat
addMessageToChat('user', message);
chatInput.value = '';
// Add typing indicator
addTypingIndicator();
// Send message to AI
sendToAI(message);
}
function addMessageToChat(sender, message, withScroll = true) {
const messageDiv = document.createElement('div');
messageDiv.className = `chat-message ${sender}-message mb-3`;
const time = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
if (sender === 'user') {
messageDiv.innerHTML = `
<div class="d-flex align-items-start justify-content-end">
<div class="message-content me-3 flex-grow-1" style="max-width: 70%;">
<div class="message-bubble bg-primary text-white p-3 rounded-3 shadow-sm">
<p class="mb-0">${message}</p>
</div>
<small class="text-muted d-block text-end mt-1">${time}</small>
</div>
<div class="avatar bg-secondary text-white rounded-circle d-flex align-items-center justify-content-center flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
<i class="fas fa-user" style="font-size: 1.1rem;"></i>
</div>
</div>
`;
} else {
messageDiv.innerHTML = `
<div class="d-flex align-items-start">
<div class="avatar bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3 flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
<i class="fas fa-cat" style="font-size: 1.2rem;"></i>
</div>
<div class="message-content flex-grow-1" style="max-width: 70%;">
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
<p class="mb-0">${message}</p>
</div>
<small class="text-muted d-block mt-1">${time}</small>
</div>
</div>
`;
}
chatContainer.appendChild(messageDiv);
if (withScroll) {
chatContainer.scrollTop = chatContainer.scrollHeight;
}
}
function addTypingIndicator() {
const typingDiv = document.createElement('div');
typingDiv.id = 'typing-indicator';
typingDiv.className = 'chat-message bot-message mb-3';
typingDiv.innerHTML = `
<div class="d-flex align-items-start">
<div class="avatar bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3 flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
<i class="fas fa-cat" style="font-size: 1.2rem;"></i>
</div>
<div class="message-content flex-grow-1">
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
<div class="typing-dots">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
`;
chatContainer.appendChild(typingDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function removeTypingIndicator() {
const typingIndicator = document.getElementById('typing-indicator');
if (typingIndicator) {
typingIndicator.remove();
}
}
async function sendToAI(message) {
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: message
})
});
const result = await response.json();
removeTypingIndicator();
if (result.success) {
addMessageToChat('bot', result.response);
} else {
addMessageToChat('bot', 'Sorry, I encountered an error. Please try again.');
}
} catch (error) {
removeTypingIndicator();
addMessageToChat('bot', 'Sorry, I\'m having trouble connecting right now. Please try again.');
}
}
async function clearChatHistory() {
if (!confirm('Are you sure you want to clear the chat history? This action cannot be undone.')) {
return;
}
try {
const response = await fetch('/api/chat/history', {
method: 'DELETE'
});
const result = await response.json();
if (result.success) {
// Clear the chat container and show welcome message
chatContainer.innerHTML = '';
addWelcomeMessage();
chatContainer.scrollTop = chatContainer.scrollHeight;
} else {
alert('Failed to clear chat history. Please try again.');
}
} catch (error) {
alert('Error clearing chat history. Please try again.');
}
}
});
</script>
<%- include('partials/footer') %>