vismem / templates /index.html
broadfield-dev's picture
Update templates/index.html
8d98122 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VisMem AI // Recursive Visual Memory</title>
<script src="https://cdn.tailwindcss.com"></script>
<!-- Markdown & Syntax Highlighting -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');
body { background-color: #050505; color: #a29bfe; font-family: 'Space Mono', monospace; }
.pixelated {
image-rendering: pixelated;
width: 100%;
border: 1px solid #6c5ce7;
box-shadow: 0 0 15px rgba(108, 92, 231, 0.2);
background: #000;
}
.panel { background: #111; border: 1px solid #333; padding: 15px; border-radius: 4px; }
.btn { background: #1a1a1a; border: 1px solid #6c5ce7; color: #6c5ce7; padding: 6px 12px; font-size: 10px; transition: 0.2s; text-transform: uppercase; }
.btn:hover { background: #6c5ce7; color: #000; cursor: pointer; }
/* Chat Styling */
.chat-bubble { padding: 10px; margin-bottom: 12px; font-size: 12px; border-left: 2px solid #6c5ce7; background: #0a0a0a; overflow-wrap: break-word;}
.system-msg { color: #fab1a0; font-style: italic; display: block; margin-top: 5px; border-top: 1px dashed #333; padding-top: 5px; }
/* Markdown Overrides */
.prose p { margin-bottom: 0.5em; }
.prose pre {
background: #1e1e1e !important;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
border: 1px solid #333;
margin: 10px 0;
}
.prose code {
font-family: 'Courier New', monospace;
font-size: 11px;
color: #e0e0e0;
}
.prose ul { list-style-type: disc; margin-left: 20px; }
.prose ol { list-style-type: decimal; margin-left: 20px; }
.prose strong { color: #fff; }
.prose a { color: #6c5ce7; text-decoration: underline; }
/* Modal for Inspection */
#inspector { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80%; height: 80%; background: #000; border: 2px solid #6c5ce7; z-index: 50; display: none; padding: 20px; overflow: auto; }
.close-btn { position: absolute; top: 10px; right: 10px; color: red; cursor: pointer; }
</style>
</head>
<body class="p-4 md:p-8 max-w-7xl mx-auto">
<!-- Header -->
<div class="flex justify-between items-end mb-6 border-b border-[#333] pb-4">
<div>
<h1 class="text-2xl font-bold text-white tracking-widest">VISMEM_AI <span class="text-xs text-[#6c5ce7]">v1.0</span></h1>
<p class="text-gray-500 text-[10px]">RECURSIVE VISUAL STORAGE // MARKDOWN ENABLED</p>
</div>
<div class="text-right">
<div class="text-[10px] text-green-500">ENGINE: ACTIVE</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- VISUALIZERS -->
<div class="lg:col-span-4 flex flex-col gap-6">
<!-- History -->
<div class="panel">
<div class="flex justify-between items-center mb-2">
<h2 class="text-xs font-bold text-white">EPISODIC LOG</h2>
<button onclick="inspect('history')" class="btn">DECODE</button>
</div>
<div class="relative w-full aspect-square mb-2">
<img id="img-history" src="" class="pixelated">
</div>
<div class="text-[10px] text-gray-500 flex justify-between">
<span id="stat-history">--</span>
<span id="usage-history">--</span>
</div>
</div>
<button onclick="wipe()" class="btn border-red-900 text-red-500 hover:bg-red-900 hover:text-white">
HARD RESET (WIPE ALL)
</button>
</div>
<!-- CHAT -->
<div class="lg:col-span-8 flex flex-col h-[85vh]">
<div id="chat-log" class="panel flex-1 overflow-y-auto mb-4 font-mono text-gray-300">
<div class="text-center text-gray-700 text-xs mt-20">
// SYSTEM READY. WAITING FOR INPUT.
</div>
</div>
<form id="chat-form" class="flex gap-2">
<input type="text" id="user-input" class="bg-[#111] border border-[#333] text-white p-3 flex-1 outline-none focus:border-[#6c5ce7]" placeholder="Type your message..." autocomplete="off">
<button type="submit" class="btn px-6 font-bold text-white bg-[#6c5ce7] text-black hover:bg-white">SEND</button>
</form>
</div>
</div>
<!-- Inspector Modal -->
<div id="inspector">
<div class="close-btn" onclick="closeInspect()">[X] CLOSE</div>
<h2 class="text-xl font-bold mb-4 text-white" id="inspect-title">MEMORY DUMP</h2>
<div id="inspect-content" class="font-mono text-xs text-green-400 whitespace-pre-wrap"></div>
</div>
<script>
const chatLog = document.getElementById('chat-log');
const userInput = document.getElementById('user-input');
// Configure Marked.js with Highlight.js
marked.setOptions({
highlight: function(code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, { language }).value;
},
langPrefix: 'hljs language-',
breaks: true,
gfm: true
});
setInterval(refreshVisuals, 2000);
async function refreshVisuals() {
try {
const r2 = await fetch('/visualize/history');
const d2 = await r2.json();
document.getElementById('img-history').src = d2.image;
document.getElementById('stat-history').textContent = d2.stats;
document.getElementById('usage-history').textContent = d2.usage;
} catch(e) {}
}
async function inspect(type) {
document.getElementById('inspector').style.display = 'block';
document.getElementById('inspect-title').innerText = `DECODING ${type.toUpperCase()} SECTOR...`;
document.getElementById('inspect-content').innerText = "Reading bytes...";
const res = await fetch(`/inspect/${type}`);
const data = await res.json();
document.getElementById('inspect-content').innerText = data.content.join('\n\n');
}
function closeInspect() {
document.getElementById('inspector').style.display = 'none';
}
document.getElementById('chat-form').addEventListener('submit', async (e) => {
e.preventDefault();
const text = userInput.value.trim();
if(!text) return;
// Add User Message (No MD for user to keep it raw/clean)
addMsg("USER", text);
userInput.value = "";
// Create AI Message Container
const aiDiv = addMsg("AI", "...");
const aiContentDiv = document.createElement("div");
aiContentDiv.className = "prose"; // Tailwind typography class hook
aiDiv.innerHTML = "<strong>AI:</strong> ";
aiDiv.appendChild(aiContentDiv);
const res = await fetch('/chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({message: text})
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let rawBuffer = "";
while(true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
rawBuffer += chunk;
// 1. Separate actual content from [SYSTEM: ...] logs
// We use Regex to isolate the system logs so Markdown doesn't mess them up
// and so we can style them differently.
// Temporary placeholder for rendering
let renderText = rawBuffer;
// Regex to find system messages
const sysRegex = /\[SYSTEM:.*?\]/g;
// We let marked parse everything, but we pre-format the system tags slightly
// to ensure they survive properly or post-process.
// Simpler approach: Render Markdown, then replace the text matching system logs with styled HTML.
let html = marked.parse(renderText);
// Highlight System Logs after markdown conversion
html = html.replace(sysRegex, (match) => {
return `<span class="system-msg">${match}</span>`;
});
aiContentDiv.innerHTML = html;
chatLog.scrollTop = chatLog.scrollHeight;
}
refreshVisuals();
});
function addMsg(role, text) {
const div = document.createElement('div');
div.className = "chat-bubble";
if(role === "USER") {
div.innerHTML = `<strong>${role}:</strong> ${text}`;
} else {
div.innerHTML = `<strong>${role}:</strong> ${text}`;
}
chatLog.appendChild(div);
chatLog.scrollTop = chatLog.scrollHeight;
return div;
}
async function wipe() {
if(confirm("Really wipe memory?")) {
await fetch('/wipe', {method:'POST'});
refreshVisuals();
}
}
refreshVisuals();
</script>
</body>
</html>