|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Educational Research Methods Chatbot</title> |
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> |
|
|
<style> |
|
|
body { |
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
|
background-color: #f8f9fa; |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
} |
|
|
.chat-container { |
|
|
max-width: 800px; |
|
|
margin: 2rem auto; |
|
|
border-radius: 10px; |
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); |
|
|
background-color: #fff; |
|
|
overflow: hidden; |
|
|
} |
|
|
.chat-header { |
|
|
background-color: #4a6fdc; |
|
|
color: white; |
|
|
padding: 1.5rem; |
|
|
text-align: center; |
|
|
} |
|
|
.chat-messages { |
|
|
height: 400px; |
|
|
overflow-y: auto; |
|
|
padding: 1rem; |
|
|
background-color: #f8f9fa; |
|
|
} |
|
|
.message { |
|
|
margin-bottom: 1rem; |
|
|
padding: 0.75rem 1rem; |
|
|
border-radius: 10px; |
|
|
max-width: 80%; |
|
|
} |
|
|
.user-message { |
|
|
background-color: #e9ecef; |
|
|
margin-left: auto; |
|
|
border-bottom-right-radius: 0; |
|
|
} |
|
|
.bot-message { |
|
|
background-color: #4a6fdc; |
|
|
color: white; |
|
|
margin-right: auto; |
|
|
border-bottom-left-radius: 0; |
|
|
} |
|
|
.chat-input { |
|
|
display: flex; |
|
|
padding: 1rem; |
|
|
background-color: #fff; |
|
|
border-top: 1px solid #e9ecef; |
|
|
} |
|
|
.chat-input input { |
|
|
flex-grow: 1; |
|
|
border: 1px solid #ced4da; |
|
|
border-radius: 20px; |
|
|
padding: 0.5rem 1rem; |
|
|
margin-right: 0.5rem; |
|
|
} |
|
|
.chat-input button { |
|
|
background-color: #4a6fdc; |
|
|
color: white; |
|
|
border: none; |
|
|
border-radius: 20px; |
|
|
padding: 0.5rem 1.5rem; |
|
|
cursor: pointer; |
|
|
} |
|
|
.chat-input button:hover { |
|
|
background-color: #3a5bbf; |
|
|
} |
|
|
.citation { |
|
|
font-size: 0.8rem; |
|
|
margin-top: 0.5rem; |
|
|
color: #6c757d; |
|
|
} |
|
|
.citation-list { |
|
|
margin-top: 1rem; |
|
|
padding: 1rem; |
|
|
background-color: #f8f9fa; |
|
|
border-radius: 5px; |
|
|
font-size: 0.9rem; |
|
|
} |
|
|
.typing-indicator { |
|
|
display: none; |
|
|
padding: 0.75rem 1rem; |
|
|
background-color: #e9ecef; |
|
|
border-radius: 10px; |
|
|
margin-bottom: 1rem; |
|
|
width: fit-content; |
|
|
} |
|
|
.typing-indicator span { |
|
|
height: 10px; |
|
|
width: 10px; |
|
|
float: left; |
|
|
margin: 0 1px; |
|
|
background-color: #9E9EA1; |
|
|
display: block; |
|
|
border-radius: 50%; |
|
|
opacity: 0.4; |
|
|
} |
|
|
.typing-indicator span:nth-of-type(1) { |
|
|
animation: 1s blink infinite 0.3333s; |
|
|
} |
|
|
.typing-indicator span:nth-of-type(2) { |
|
|
animation: 1s blink infinite 0.6666s; |
|
|
} |
|
|
.typing-indicator span:nth-of-type(3) { |
|
|
animation: 1s blink infinite 0.9999s; |
|
|
} |
|
|
@keyframes blink { |
|
|
50% { |
|
|
opacity: 1; |
|
|
} |
|
|
} |
|
|
.model-info { |
|
|
font-size: 0.8rem; |
|
|
text-align: center; |
|
|
margin-top: 1rem; |
|
|
color: #6c757d; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<div class="chat-container"> |
|
|
<div class="chat-header"> |
|
|
<h1>Educational Research Methods Chatbot</h1> |
|
|
<p>Ask questions about research methods for educational research</p> |
|
|
</div> |
|
|
<div class="chat-messages" id="chat-messages"> |
|
|
<div class="message bot-message"> |
|
|
Hello! I'm your educational research methods assistant. I can help you choose appropriate research methods for your educational research projects. What would you like to know? |
|
|
</div> |
|
|
<div class="typing-indicator" id="typing-indicator"> |
|
|
<span></span> |
|
|
<span></span> |
|
|
<span></span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="chat-input"> |
|
|
<input type="text" id="user-input" placeholder="Type your question here..."> |
|
|
<button id="send-button">Send</button> |
|
|
</div> |
|
|
<div class="model-info"> |
|
|
Powered by Mistral-7B-v0.1 - Open Source LLM |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
const chatMessages = document.getElementById('chat-messages'); |
|
|
const userInput = document.getElementById('user-input'); |
|
|
const sendButton = document.getElementById('send-button'); |
|
|
const typingIndicator = document.getElementById('typing-indicator'); |
|
|
|
|
|
|
|
|
const API_ENDPOINT = '/.netlify/functions/chat-mistral'; |
|
|
|
|
|
let conversationHistory = []; |
|
|
|
|
|
|
|
|
function addMessage(message, isUser = false) { |
|
|
const messageDiv = document.createElement('div'); |
|
|
messageDiv.classList.add('message'); |
|
|
messageDiv.classList.add(isUser ? 'user-message' : 'bot-message'); |
|
|
|
|
|
|
|
|
if (!isUser && typeof message === 'object') { |
|
|
const messageText = document.createElement('div'); |
|
|
messageText.textContent = message.response; |
|
|
messageDiv.appendChild(messageText); |
|
|
|
|
|
|
|
|
if (message.citations && message.citations.length > 0) { |
|
|
const citationList = document.createElement('div'); |
|
|
citationList.classList.add('citation-list'); |
|
|
citationList.innerHTML = '<strong>References:</strong>'; |
|
|
|
|
|
const citationUl = document.createElement('ul'); |
|
|
message.citations.forEach(citation => { |
|
|
const citationLi = document.createElement('li'); |
|
|
citationLi.textContent = citation.text; |
|
|
citationUl.appendChild(citationLi); |
|
|
}); |
|
|
|
|
|
citationList.appendChild(citationUl); |
|
|
messageDiv.appendChild(citationList); |
|
|
} |
|
|
} else { |
|
|
messageDiv.textContent = message; |
|
|
} |
|
|
|
|
|
chatMessages.appendChild(messageDiv); |
|
|
chatMessages.scrollTop = chatMessages.scrollHeight; |
|
|
} |
|
|
|
|
|
|
|
|
function showTypingIndicator() { |
|
|
typingIndicator.style.display = 'block'; |
|
|
chatMessages.scrollTop = chatMessages.scrollHeight; |
|
|
} |
|
|
|
|
|
|
|
|
function hideTypingIndicator() { |
|
|
typingIndicator.style.display = 'none'; |
|
|
} |
|
|
|
|
|
|
|
|
async function sendMessage(message) { |
|
|
try { |
|
|
showTypingIndicator(); |
|
|
|
|
|
const response = await fetch(API_ENDPOINT, { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Content-Type': 'application/json' |
|
|
}, |
|
|
body: JSON.stringify({ |
|
|
message: message, |
|
|
conversation_history: conversationHistory |
|
|
}) |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
throw new Error('API request failed'); |
|
|
} |
|
|
|
|
|
const data = await response.json(); |
|
|
hideTypingIndicator(); |
|
|
|
|
|
|
|
|
addMessage(data, false); |
|
|
|
|
|
|
|
|
conversationHistory.push({ |
|
|
message: message, |
|
|
response: data.response |
|
|
}); |
|
|
|
|
|
|
|
|
if (conversationHistory.length > 10) { |
|
|
conversationHistory = conversationHistory.slice(-10); |
|
|
} |
|
|
} catch (error) { |
|
|
hideTypingIndicator(); |
|
|
console.error('Error:', error); |
|
|
addMessage('Sorry, I encountered an error. The Hugging Face Inference API may be temporarily unavailable. Please try again later.', false); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
sendButton.addEventListener('click', function() { |
|
|
const message = userInput.value.trim(); |
|
|
if (message) { |
|
|
addMessage(message, true); |
|
|
userInput.value = ''; |
|
|
sendMessage(message); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
userInput.addEventListener('keypress', function(e) { |
|
|
if (e.key === 'Enter') { |
|
|
const message = userInput.value.trim(); |
|
|
if (message) { |
|
|
addMessage(message, true); |
|
|
userInput.value = ''; |
|
|
sendMessage(message); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
userInput.focus(); |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|