Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions chat.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scholarly - AI Study Buddy</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<!-- Navigation Bar -->
<nav id="navbar" class="navbar">
<ul class="navbar-nav">
<li class="nav-item">
<a href="index.html" class="nav-link">
<i class="fas fa-tasks"></i>
<span class="link-text">Quests</span>
</a>
</li>
<li class="nav-item">
<a href="chat.html" class="nav-link">
<i class="fas fa-robot"></i>
<span class="link-text">AI Buddy</span>
</a>
</li>
<li class="nav-item">
<a href="resources.html" class="nav-link">
<i class="fas fa-book"></i>
<span class="link-text">Resources</span>
</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link logout-link">
<i class="fas fa-sign-out-alt"></i>
<span class="link-text">Logout</span>
</a>
</li>
</ul>
</nav>

<main class="chat-container">
<div class="chat-header">
<h1>🤖 AI Study Buddy</h1>
<button id="clear-chat-btn" class="action-btn" style="background-color: #3e4a61;">
<i class="fas fa-trash"></i> Clear Chat
</button>
<div class="subject-selector">
<label for="chat-subject">Subject Context:</label>
<select id="chat-subject">
<option value="">General</option>
</select>
</div>
</div>

<div id="chat-window" class="chat-window">
<div class="message bot-message">
<p>Hello! I'm Scholarly, your AI Study Buddy! 📚</p>
<p>I'm here to help you with your studies. I know you're studying <span id="student-info-chat"></span>.</p>
<p>What would you like to learn about today?</p>
</div>
</div>

<div class="chat-input-area">
<textarea id="chat-input" placeholder="Ask me anything about your subjects..." rows="2"></textarea>
<button id="send-btn">
<i class="fas fa-paper-plane"></i>
</button>
</div>

<!-- Quick prompts for common questions -->
<div id="quick-prompts" style="margin-top: 10px; display: flex; gap: 5px; flex-wrap: wrap;">
<button class="quick-prompt" data-prompt="Explain this concept in simple terms">Explain Simply</button>
<button class="quick-prompt" data-prompt="Give me an example">Give Example</button>
<button class="quick-prompt" data-prompt="How is this useful in real life?">Real Life Use</button>
<button class="quick-prompt" data-prompt="Create a practice question">Practice Question</button>
<button class="quick-prompt" data-prompt="Summarize this chapter">Summarize</button>
</div>
</main>

<style>
.quick-prompt {
padding: 5px 10px;
background-color: #0f3460;
color: #e0e0e0;
border: 1px solid #e94560;
border-radius: 5px;
cursor: pointer;
font-size: 0.85rem;
transition: all 0.3s;
}
.quick-prompt:hover {
background-color: #e94560;
color: white;
}
</style>

<script src="chat.js"></script>
</body>
</html>
177 changes: 177 additions & 0 deletions chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// File: chat.js (Complete and Final Code)
document.addEventListener('DOMContentLoaded', () => {
const API_URL = "http://localhost:5000";

// State variables
let userInfo = null;
let studentInfo = null;
let chatHistory = JSON.parse(localStorage.getItem('chatHistory')) || [];
let currentSubject = '';

// DOM Elements
const chatWindow = document.getElementById('chat-window');
const chatInput = document.getElementById('chat-input');
const sendBtn = document.getElementById('send-btn');
const subjectSelect = document.getElementById('chat-subject');
const quickPrompts = document.querySelectorAll('.quick-prompt');

async function init() {
try {
// Securely fetch user data from the server based on the session cookie
const meResponse = await fetch(`${API_URL}/api/me`, { credentials: 'include' });
if (!meResponse.ok) {
// If not authenticated, redirect to the login page
window.location.href = 'login.html';
return;
}
const meData = await meResponse.json();
userInfo = meData.loggedInUser;
studentInfo = meData.studentInfo;

// Now that we are authenticated, load the chat content
displayStudentInfo();
await loadSubjects();
loadChatHistory();
setupEventListeners();
} catch (error) {
console.error("Chat Initialization Error:", error);
window.location.href = 'login.html';
}
}

function displayStudentInfo() {
if (studentInfo) {
const infoText = `${studentInfo.board} Board, Class ${studentInfo.class}${studentInfo.stream ? ' (' + studentInfo.stream + ')' : ''}`;
document.getElementById('student-info-chat').textContent = infoText;
}
}

async function loadSubjects() {
try {
const res = await fetch(`${API_URL}/api/subjects/${studentInfo?.class}/${studentInfo?.stream || ''}`);
if (res.ok) {
const subjects = await res.json();
const customSubjects = JSON.parse(localStorage.getItem('customSubjects')) || [];
[...subjects, ...customSubjects].forEach(subject => {
const option = document.createElement('option');
option.value = subject;
option.textContent = subject;
subjectSelect.appendChild(option);
});
}
} catch (err) {
console.error('Error loading subjects:', err);
}
}

function loadChatHistory() {
chatHistory.slice(-10).forEach(msg => appendMessage(msg.text, msg.sender, false));
if (chatHistory.length > 0) chatWindow.scrollTop = chatWindow.scrollHeight;
}

async function sendMessage() {
const messageText = chatInput.value.trim();
if (!messageText) return;

appendMessage(messageText, 'user');
chatInput.value = '';
chatInput.style.height = 'auto';

const typingIndicator = showTypingIndicator();

try {
const res = await fetch(`${API_URL}/api/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ message: messageText, subject: currentSubject || null })
});

if (!res.ok) throw new Error('Server error');
const data = await res.json();

chatWindow.removeChild(typingIndicator);
appendMessage(data.reply, 'bot');

} catch (error) {
console.error('Chat error:', error);
if (typingIndicator?.parentNode) chatWindow.removeChild(typingIndicator);
appendMessage("Sorry, I couldn't connect to the server. Please try again later.", 'bot');
}
}

function appendMessage(text, sender, save = true) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${sender}-message`);
messageDiv.innerHTML = formatMessage(text);
chatWindow.appendChild(messageDiv);
chatWindow.scrollTop = chatWindow.scrollHeight;

if (save) {
chatHistory.push({ text, sender });
localStorage.setItem('chatHistory', JSON.stringify(chatHistory.slice(-50)));
}
}

function formatMessage(text) {
return text.split('\n').filter(p => p.trim()).map(p => {
p = p.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>').replace(/\*(.*?)\*/g, '<em>$1</em>').replace(/`(.*?)`/g, '<code>$1</code>');
if (p.startsWith('- ')) p = '• ' + p.substring(2);
return `<p>${p}</p>`;
}).join('');
}

function showTypingIndicator() {
const typingDiv = document.createElement('div');
typingDiv.className = 'message bot-message typing-indicator';
typingDiv.innerHTML = '<span></span><span></span><span></span>';
chatWindow.appendChild(typingDiv);
chatWindow.scrollTop = chatWindow.scrollHeight;
return typingDiv;
}

function setupEventListeners() {
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } });
chatInput.addEventListener('input', () => { chatInput.style.height = 'auto'; chatInput.style.height = `${chatInput.scrollHeight}px`; });
subjectSelect.addEventListener('change', e => { currentSubject = e.target.value; });
quickPrompts.forEach(btn => btn.addEventListener('click', () => { chatInput.value += ` ${btn.dataset.prompt}`; chatInput.focus(); }));


const clearChatBtn = document.getElementById('clear-chat-btn');
if (clearChatBtn) {
clearChatBtn.addEventListener('click', async () => {
if (confirm("Are you sure you want to delete your entire chat history? This cannot be undone.")) {
try {
const res = await fetch(`${API_URL}/api/chat/history`, {
method: 'DELETE',
credentials: 'include'
});

if (res.ok) {
// Clear the chat window on the frontend
chatWindow.innerHTML = '<div class="message bot-message"><p>Chat history cleared. How can I help you start fresh?</p></div>';
// Clear the history from local storage as well
localStorage.removeItem('chatHistory');
chatHistory = [];
} else {
alert("Failed to clear chat history.");
}
} catch (error) {
console.error("Clear chat error:", error);
alert("Could not connect to the server to clear history.");
}
}
});
}

document.querySelector('.logout-link').addEventListener('click', async e => {
e.preventDefault();
await fetch(`${API_URL}/logout`, { method: 'POST', credentials: 'include' });
localStorage.clear();
window.location.href = 'login.html';
});
}

init();
});
Loading