Spaces:
Running
Running
<html> | |
<head> | |
<title>RAG Chatbot</title> | |
<style> | |
:root { | |
--primary-color: #a0a0a0; | |
--background-color: #1a1a1a; | |
--card-background: #2d2d2d; | |
--text-color: #e0e0e0; | |
--border-radius: 6px; | |
--shadow: 0 4px 6px rgba(0, 0, 0, 0.3); | |
--input-background: #363636; | |
--input-border: #404040; | |
} | |
body { | |
font-family: 'Segoe UI', Arial, sans-serif; | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
background-color: var(--background-color); | |
color: var(--text-color); | |
} | |
.card { | |
background: var(--card-background); | |
border-radius: var(--border-radius); | |
box-shadow: var(--shadow); | |
padding: 2rem; | |
margin: 2rem 0; | |
} | |
.chat-container { | |
background: var(--card-background); | |
border-radius: var(--border-radius); | |
padding: 1.5rem; | |
height: 700px; | |
overflow-y: auto; | |
margin-bottom: 1.5rem; | |
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05); | |
border: 1px solid var(--input-border); | |
} | |
.message { | |
margin-bottom: 1rem; | |
padding: 1rem; | |
border-radius: 4px; | |
max-width: 70%; | |
animation: fadeIn 0.3s ease; | |
} | |
@keyframes fadeIn { | |
from { | |
opacity: 0; | |
transform: translateY(10px); | |
} | |
to { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
} | |
.user-message { | |
background-color: #808080; | |
margin-left: auto; | |
color: #ffffff; | |
box-shadow: 0 2px 4px rgba(128, 128, 128, 0.2); | |
} | |
.bot-message { | |
background-color: #363636; | |
margin-right: auto; | |
color: #e0e0e0; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); | |
} | |
.loading-dots { | |
display: inline-block; | |
} | |
@keyframes dots { | |
0% { | |
content: ''; | |
} | |
25% { | |
content: '.'; | |
} | |
50% { | |
content: '..'; | |
} | |
75% { | |
content: '...'; | |
} | |
100% { | |
content: ''; | |
} | |
} | |
.loading-dots::after { | |
content: ''; | |
animation: dots 2s infinite; | |
display: inline-block; | |
width: 1em; | |
} | |
.input-container { | |
display: flex; | |
gap: 12px; | |
padding: 1rem; | |
background: var(--card-background); | |
border-radius: var(--border-radius); | |
box-shadow: var(--shadow); | |
} | |
.nav { | |
background: var(--card-background); | |
padding: 1rem; | |
border-radius: var(--border-radius); | |
box-shadow: var(--shadow); | |
margin-bottom: 1rem; | |
} | |
.nav a { | |
margin-right: 20px; | |
text-decoration: none; | |
color: var(--primary-color); | |
font-weight: 500; | |
padding: 0.5rem 1rem; | |
border-radius: 4px; | |
transition: all 0.3s ease; | |
} | |
.nav a:hover { | |
background: #363636; | |
} | |
#messageInput { | |
flex-grow: 1; | |
padding: 12px; | |
border: 2px solid var(--input-border); | |
border-radius: 4px; | |
font-size: 1rem; | |
transition: all 0.3s ease; | |
background: var(--input-background); | |
color: var(--text-color); | |
} | |
#messageInput:focus { | |
outline: none; | |
border-color: var(--primary-color); | |
box-shadow: 0 0 0 3px rgba(114, 137, 218, 0.1); | |
} | |
button { | |
background: var(--primary-color); | |
color: white; | |
border: none; | |
padding: 12px 24px; | |
border-radius: 4px; | |
cursor: pointer; | |
font-size: 1rem; | |
transition: all 0.3s ease; | |
} | |
button:hover { | |
background: #909090; | |
transform: translateY(-2px); | |
} | |
h1 { | |
color: var(--primary-color); | |
text-align: center; | |
margin-bottom: 1.5rem; | |
} | |
/* Scrollbar styling */ | |
.chat-container::-webkit-scrollbar { | |
width: 8px; | |
} | |
.chat-container::-webkit-scrollbar-track { | |
background: #363636; | |
} | |
.chat-container::-webkit-scrollbar-thumb { | |
background: #4a4a4a; | |
} | |
.chat-container::-webkit-scrollbar-thumb:hover { | |
background: #5a5a5a; | |
} | |
/* Add these new styles */ | |
.main-container { | |
display: flex; | |
gap: 20px; | |
height: calc(100vh - 100px); | |
/* Adjust for nav and padding */ | |
} | |
.chat-card { | |
flex: 3; | |
background: var(--card-background); | |
border-radius: var(--border-radius); | |
box-shadow: var(--shadow); | |
padding: 2rem; | |
margin: 1rem 0; | |
display: flex; | |
flex-direction: column; | |
height: fit-content; | |
} | |
.sources-card { | |
flex: 1; | |
background: var(--card-background); | |
border-radius: var(--border-radius); | |
box-shadow: var(--shadow); | |
padding: 2rem; | |
margin: 1rem 0; | |
min-width: 250px; | |
display: flex; | |
flex-direction: column; | |
height: auto; | |
} | |
.source-item { | |
padding: 10px; | |
margin-bottom: 10px; | |
background: var(--input-background); | |
border-radius: var(--border-radius); | |
font-size: 0.9rem; | |
border: 1px solid var(--input-border); | |
} | |
.sources-title { | |
color: var(--text-color); | |
font-size: 1.2rem; | |
margin-bottom: 1rem; | |
padding-bottom: 0.5rem; | |
border-bottom: 1px solid var(--input-border); | |
} | |
#sourcesContainer { | |
flex: 1; | |
overflow-y: auto; | |
} | |
.logo-container { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
margin-bottom: 1rem; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="nav"> | |
<a href="/">Upload</a> | |
<a href="/chat">Chat</a> | |
</div> | |
<div class="main-container"> | |
<div class="chat-card"> | |
<div class="logo-container"> | |
<img src="./static/Matriv-white.png" alt="Matriv Logo" style="width: 100px; height: auto;"> | |
</div> | |
<div class="chat-container" id="chatContainer"> | |
</div> | |
<div class="input-container"> | |
<input type="text" id="messageInput" placeholder="Type your message..."> | |
<button onclick="sendMessage()">Send</button> | |
</div> | |
</div> | |
<div class="sources-card"> | |
<h2 class="sources-title">Sources</h2> | |
<div id="sourcesContainer"></div> | |
</div> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
<script> | |
const chatContainer = document.getElementById('chatContainer'); | |
const messageInput = document.getElementById('messageInput'); | |
const sourcesContainer = document.getElementById('sourcesContainer'); | |
function addMessage(message, isUser) { | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`; | |
messageDiv.textContent = message; | |
chatContainer.appendChild(messageDiv); | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
return messageDiv; | |
} | |
function updateSources(sources) { | |
sourcesContainer.innerHTML = ''; | |
if (sources && sources.length > 0) { | |
sources.forEach(source => { | |
const sourceDiv = document.createElement('div'); | |
sourceDiv.className = 'source-item'; | |
sourceDiv.textContent = source; | |
sourcesContainer.appendChild(sourceDiv); | |
}); | |
} | |
} | |
async function sendMessage() { | |
const message = messageInput.value.trim(); | |
if (!message) return; | |
addMessage(message, true); | |
messageInput.value = ''; | |
// Add loading message | |
const loadingDiv = document.createElement('div'); | |
loadingDiv.className = 'message bot-message'; | |
const loadingSpan = document.createElement('span'); | |
loadingSpan.className = 'loading-dots'; | |
loadingSpan.textContent = 'Thinking'; | |
loadingDiv.appendChild(loadingSpan); | |
chatContainer.appendChild(loadingDiv); | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
try { | |
const response = await fetch('/chat', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ question: message }), | |
}); | |
const data = await response.json(); | |
// Remove loading message | |
chatContainer.removeChild(loadingDiv); | |
if (data.error) { | |
addMessage(data.error, false); | |
return; | |
} | |
// Create a temporary div to render markdown | |
const tempDiv = document.createElement('div'); | |
tempDiv.innerHTML = marked.parse(data.answer[0]); | |
// Create message div with markdown content | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = 'message bot-message'; | |
messageDiv.innerHTML = tempDiv.innerHTML; | |
chatContainer.appendChild(messageDiv); | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
// Update sources if they exist in the response | |
if (data.answer[1]) { | |
updateSources(data.answer[1]); | |
} | |
} catch (error) { | |
// Remove loading message | |
chatContainer.removeChild(loadingDiv); | |
console.error('Error:', error); | |
addMessage('Sorry, there was an error processing your message.', false); | |
} | |
} | |
messageInput.addEventListener('keypress', function (e) { | |
if (e.key === 'Enter') { | |
sendMessage(); | |
} | |
}); | |
</script> | |
</body> | |
</html> |