554 lines
16 KiB
HTML
554 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Mem0 Chat Interface</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background-color: #f5f5f5;
|
|
height: 100vh;
|
|
display: flex;
|
|
}
|
|
|
|
.container {
|
|
display: flex;
|
|
width: 100%;
|
|
height: 100vh;
|
|
}
|
|
|
|
/* Chat Section */
|
|
.chat-section {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: white;
|
|
border-right: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.chat-header {
|
|
padding: 20px;
|
|
background: #fafafa;
|
|
border-bottom: 1px solid #e0e0e0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.chat-header-content {
|
|
text-align: center;
|
|
flex: 1;
|
|
}
|
|
|
|
.chat-header h1 {
|
|
font-size: 24px;
|
|
color: #333;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.chat-header p {
|
|
color: #666;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.clear-chat-btn {
|
|
background: #f8f9fa;
|
|
color: #666;
|
|
border: 1px solid #e0e0e0;
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.clear-chat-btn:hover {
|
|
background: #e9ecef;
|
|
border-color: #ced4da;
|
|
color: #495057;
|
|
}
|
|
|
|
.clear-chat-btn:active {
|
|
background: #dee2e6;
|
|
}
|
|
|
|
.chat-messages {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
}
|
|
|
|
.message {
|
|
max-width: 80%;
|
|
padding: 12px 16px;
|
|
border-radius: 18px;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
.message.user {
|
|
align-self: flex-end;
|
|
background: #007bff;
|
|
color: white;
|
|
}
|
|
|
|
.message.assistant {
|
|
align-self: flex-start;
|
|
background: #f1f1f1;
|
|
color: #333;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.message-metadata {
|
|
font-size: 11px;
|
|
color: #888;
|
|
margin-top: 6px;
|
|
font-style: italic;
|
|
}
|
|
|
|
.chat-input {
|
|
padding: 20px;
|
|
background: white;
|
|
border-top: 1px solid #e0e0e0;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.chat-input input {
|
|
flex: 1;
|
|
padding: 12px 16px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
outline: none;
|
|
}
|
|
|
|
.chat-input input:focus {
|
|
border-color: #007bff;
|
|
}
|
|
|
|
.chat-input button {
|
|
padding: 12px 20px;
|
|
background: #007bff;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 20px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.chat-input button:hover {
|
|
background: #0056b3;
|
|
}
|
|
|
|
.chat-input button:disabled {
|
|
background: #ccc;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Memories Section */
|
|
.memories-section {
|
|
width: 350px;
|
|
background: white;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.memories-header {
|
|
padding: 20px;
|
|
background: #fafafa;
|
|
border-bottom: 1px solid #e0e0e0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.memories-header h2 {
|
|
font-size: 18px;
|
|
color: #333;
|
|
}
|
|
|
|
.refresh-btn {
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
color: #666;
|
|
padding: 5px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.refresh-btn:hover {
|
|
background: #f0f0f0;
|
|
}
|
|
|
|
.memories-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 10px;
|
|
}
|
|
|
|
.memory-item {
|
|
background: #f9f9f9;
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
margin-bottom: 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.memory-content {
|
|
font-size: 14px;
|
|
color: #333;
|
|
margin-bottom: 8px;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.memory-meta {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
|
|
.memory-timestamp {
|
|
font-size: 11px;
|
|
}
|
|
|
|
.delete-btn {
|
|
background: #ff4757;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
padding: 4px 8px;
|
|
cursor: pointer;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.delete-btn:hover {
|
|
background: #ff3742;
|
|
}
|
|
|
|
.loading {
|
|
text-align: center;
|
|
padding: 20px;
|
|
color: #666;
|
|
font-style: italic;
|
|
}
|
|
|
|
.error {
|
|
background: #ffe6e6;
|
|
border: 1px solid #ffcccc;
|
|
color: #cc0000;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
margin: 10px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 768px) {
|
|
.memories-section {
|
|
width: 280px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<!-- Chat Section -->
|
|
<div class="chat-section">
|
|
<div class="chat-header">
|
|
<div class="chat-header-content">
|
|
<h1>What can I help you with?</h1>
|
|
<p>Chat with your memories - User: pratik</p>
|
|
</div>
|
|
<button class="clear-chat-btn" id="clearChatBtn" title="Clear chat history">
|
|
🗑️ Clear Chat
|
|
</button>
|
|
</div>
|
|
|
|
<div class="chat-messages" id="chatMessages">
|
|
<!-- Messages will be loaded here -->
|
|
</div>
|
|
|
|
<div class="chat-input">
|
|
<input type="text" id="messageInput" placeholder="Type a message..." maxlength="1000">
|
|
<button id="sendButton">Send</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Memories Section -->
|
|
<div class="memories-section">
|
|
<div class="memories-header">
|
|
<h2>Your Memories (<span id="memoryCount">0</span>)</h2>
|
|
<button class="refresh-btn" id="refreshMemories" title="Refresh memories">🔄</button>
|
|
</div>
|
|
|
|
<div class="memories-list" id="memoriesList">
|
|
<div class="loading">Loading memories...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Configuration
|
|
const API_BASE = 'http://localhost:8000';
|
|
const USER_ID = 'pratik';
|
|
|
|
// DOM Elements
|
|
const chatMessages = document.getElementById('chatMessages');
|
|
const messageInput = document.getElementById('messageInput');
|
|
const sendButton = document.getElementById('sendButton');
|
|
const memoriesList = document.getElementById('memoriesList');
|
|
const memoryCount = document.getElementById('memoryCount');
|
|
const refreshButton = document.getElementById('refreshMemories');
|
|
const clearChatBtn = document.getElementById('clearChatBtn');
|
|
|
|
// Chat history in localStorage
|
|
let chatHistory = JSON.parse(localStorage.getItem('chatHistory') || '[]');
|
|
|
|
// Initialize
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadChatHistory();
|
|
loadMemories();
|
|
|
|
// Event listeners
|
|
sendButton.addEventListener('click', sendMessage);
|
|
messageInput.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') sendMessage();
|
|
});
|
|
refreshButton.addEventListener('click', loadMemories);
|
|
clearChatBtn.addEventListener('click', clearChatWithConfirmation);
|
|
});
|
|
|
|
// Load chat history from localStorage
|
|
function loadChatHistory() {
|
|
chatMessages.innerHTML = '';
|
|
chatHistory.forEach(item => {
|
|
displayMessage(item.message, item.isUser);
|
|
});
|
|
scrollToBottom();
|
|
}
|
|
|
|
// Save message to localStorage
|
|
function saveMessage(message, isUser) {
|
|
chatHistory.push({
|
|
message,
|
|
isUser,
|
|
timestamp: Date.now()
|
|
});
|
|
localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
|
|
}
|
|
|
|
// Display message in chat
|
|
function displayMessage(message, isUser, metadata = null) {
|
|
const messageDiv = document.createElement('div');
|
|
messageDiv.className = `message ${isUser ? 'user' : 'assistant'}`;
|
|
messageDiv.textContent = message;
|
|
|
|
// Add metadata for assistant messages
|
|
if (!isUser && metadata) {
|
|
const metadataDiv = document.createElement('div');
|
|
metadataDiv.className = 'message-metadata';
|
|
metadataDiv.textContent = `📊 ${metadata.memories_used || 0} memories used • ${metadata.model_used || 'unknown model'}`;
|
|
messageDiv.appendChild(metadataDiv);
|
|
}
|
|
|
|
chatMessages.appendChild(messageDiv);
|
|
scrollToBottom();
|
|
}
|
|
|
|
// Scroll to bottom of chat
|
|
function scrollToBottom() {
|
|
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
}
|
|
|
|
// Send message
|
|
async function sendMessage() {
|
|
const message = messageInput.value.trim();
|
|
if (!message) return;
|
|
|
|
// Disable input
|
|
sendButton.disabled = true;
|
|
messageInput.disabled = true;
|
|
|
|
// Display user message
|
|
displayMessage(message, true);
|
|
saveMessage(message, true);
|
|
messageInput.value = '';
|
|
|
|
try {
|
|
// Get last 50 messages from localStorage as context
|
|
const context = chatHistory.slice(-50).map(item => ({
|
|
role: item.isUser ? "user" : "assistant",
|
|
content: item.message
|
|
}));
|
|
|
|
// Send to backend with context
|
|
const response = await fetch(`${API_BASE}/chat`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
message: message,
|
|
user_id: USER_ID,
|
|
context: context
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Display assistant response with metadata
|
|
if (data.response) {
|
|
displayMessage(data.response, false, {
|
|
memories_used: data.memories_used,
|
|
model_used: data.model_used
|
|
});
|
|
saveMessage(data.response, false);
|
|
}
|
|
|
|
// Refresh memories after chat
|
|
setTimeout(() => loadMemories(), 500);
|
|
|
|
} catch (error) {
|
|
console.error('Error sending message:', error);
|
|
displayMessage('Sorry, there was an error processing your message. Please try again.', false);
|
|
showError('Failed to send message: ' + error.message);
|
|
} finally {
|
|
// Re-enable input
|
|
sendButton.disabled = false;
|
|
messageInput.disabled = false;
|
|
messageInput.focus();
|
|
}
|
|
}
|
|
|
|
// Load memories from backend
|
|
async function loadMemories() {
|
|
try {
|
|
const response = await fetch(`${API_BASE}/memories/${USER_ID}?limit=50`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const memories = await response.json();
|
|
displayMemories(memories);
|
|
|
|
} catch (error) {
|
|
console.error('Error loading memories:', error);
|
|
memoriesList.innerHTML = `<div class="error">Failed to load memories: ${error.message}</div>`;
|
|
}
|
|
}
|
|
|
|
// Display memories in sidebar
|
|
function displayMemories(memories) {
|
|
memoryCount.textContent = memories.length;
|
|
|
|
if (memories.length === 0) {
|
|
memoriesList.innerHTML = '<div class="loading">No memories yet. Start chatting to create some!</div>';
|
|
return;
|
|
}
|
|
|
|
memoriesList.innerHTML = '';
|
|
|
|
memories.forEach(memory => {
|
|
const memoryDiv = document.createElement('div');
|
|
memoryDiv.className = 'memory-item';
|
|
|
|
const content = memory.memory || memory.content || 'No content';
|
|
const timestamp = memory.created_at ? new Date(memory.created_at).toLocaleString() : 'Unknown time';
|
|
|
|
memoryDiv.innerHTML = `
|
|
<div class="memory-content">${content}</div>
|
|
<div class="memory-meta">
|
|
<span class="memory-timestamp">${timestamp}</span>
|
|
<button class="delete-btn" onclick="deleteMemory('${memory.id}')">Delete</button>
|
|
</div>
|
|
`;
|
|
|
|
memoriesList.appendChild(memoryDiv);
|
|
});
|
|
}
|
|
|
|
// Delete memory
|
|
async function deleteMemory(memoryId) {
|
|
if (!confirm('Are you sure you want to delete this memory?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${API_BASE}/memories/${memoryId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
// Refresh memories list
|
|
loadMemories();
|
|
|
|
} catch (error) {
|
|
console.error('Error deleting memory:', error);
|
|
showError('Failed to delete memory: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Show error message
|
|
function showError(message) {
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'error';
|
|
errorDiv.textContent = message;
|
|
|
|
// Insert at top of memories list
|
|
memoriesList.insertBefore(errorDiv, memoriesList.firstChild);
|
|
|
|
// Remove after 5 seconds
|
|
setTimeout(() => {
|
|
if (errorDiv.parentNode) {
|
|
errorDiv.parentNode.removeChild(errorDiv);
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
// Clear chat history with confirmation
|
|
function clearChatWithConfirmation() {
|
|
if (confirm('Are you sure you want to clear the chat history? This action cannot be undone.')) {
|
|
clearChatHistory();
|
|
}
|
|
}
|
|
|
|
// Clear chat history (for debugging)
|
|
function clearChatHistory() {
|
|
chatHistory = [];
|
|
localStorage.removeItem('chatHistory');
|
|
chatMessages.innerHTML = '';
|
|
console.log('Chat history cleared');
|
|
}
|
|
|
|
// Make clearChatHistory available globally for debugging
|
|
window.clearChatHistory = clearChatHistory;
|
|
</script>
|
|
</body>
|
|
</html>
|