RAG-Visualizer / index.html
quickgrid's picture
Update index.html
afd8fb2 verified
raw
history blame
4.93 kB
<!DOCTYPE html>
<html lang="en" class="h-full bg-gray-950 text-gray-100">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RAG Visualizer • Browser RAG</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2"></script>
<!-- Add other CDNs if needed: e.g., for charts or flow -->
<style>
/* Custom styles for highlights, nodes, etc. */
.vector-row { transition: all 0.3s; }
.highlight { animation: pulse 1.5s; background-color: #4f46e5; }
@keyframes pulse { 0%,100% {opacity:1} 50% {opacity:0.7} }
.node { border: 2px solid #6366f1; }
</style>
</head>
<body class="h-screen flex flex-col overflow-hidden">
<header class="bg-gray-900 p-4 border-b border-gray-700 flex justify-between">
<h1 class="text-2xl font-bold">Browser RAG Visualizer</h1>
<div id="status" class="text-sm text-green-400">Models loading...</div>
</header>
<div class="flex flex-1 overflow-hidden">
<!-- Left: Chat -->
<div class="w-1/3 border-r border-gray-700 flex flex-col">
<div id="chat" class="flex-1 p-4 overflow-y-auto space-y-4"></div>
<div class="p-4 border-t border-gray-700">
<input id="chatInput" type="text" class="w-full bg-gray-800 p-3 rounded" placeholder="Ask a question...">
</div>
</div>
<!-- Main Area -->
<div class="flex-1 flex flex-col">
<!-- Node Flow -->
<div class="h-1/3 border-b border-gray-700 p-4 overflow-auto" id="flow">
<!-- Simplified nodes: draggable divs or SVG -->
<div class="flex gap-4">
<div class="node p-4 rounded bg-gray-800 min-w-32">Embed</div>
<div class="node p-4 rounded bg-gray-800 min-w-32">Store (VectorDB)</div>
<div class="node p-4 rounded bg-gray-800 min-w-32">Retrieve Top-K</div>
<div class="node p-4 rounded bg-gray-800 min-w-32">Rerank</div>
<div class="node p-4 rounded bg-gray-800 min-w-32">Generate</div>
</div>
</div>
<!-- Vector Table & Controls -->
<div class="flex-1 p-4 overflow-auto">
<h2 class="text-lg mb-2">Vector Database</h2>
<button onclick="addEntry()" class="bg-indigo-600 px-4 py-2 rounded mb-4">Add Entry</button>
<table class="w-full" id="vectorTable">
<thead><tr><th>Text</th><th>Metadata</th><th>Date</th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<!-- Right: Details -->
<div class="w-1/4 border-l border-gray-700 p-4 overflow-y-auto">
<h2>Top-K / Context</h2>
<div id="topk"></div>
<h2 class="mt-6">Reranking</h2>
<div id="rerank"></div>
</div>
</div>
<script>
// Global state
let vectors = []; // {id, text, embedding, metadata, date}
let embedder, generator, reranker;
async function initModels() {
const status = document.getElementById('status');
status.textContent = 'Loading embedding model...';
embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', { device: 'webgpu' }); // or 'wasm'
status.textContent = 'Loading LLM...';
// generator = await pipeline('text-generation', 'Xenova/Qwen2.5-0.5B-Instruct', { device: 'webgpu', dtype: 'q4' });
status.textContent = 'Ready!';
}
async function getEmbedding(text) {
const output = await embedder(text, { pooling: 'mean', normalize: true });
return Array.from(output.data);
}
async function addEntry() {
const text = prompt("Enter text to add:");
if (!text) return;
const emb = await getEmbedding(text);
vectors.push({
id: Date.now(),
text,
embedding: emb,
metadata: { source: "user" },
date: new Date().toISOString()
});
renderTable();
// Animate node
}
function cosineSimilarity(a, b) {
// Simple implementation
let dot = 0, magA = 0, magB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
magA += a[i] ** 2;
magB += b[i] ** 2;
}
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
}
async function search(query, k=5) {
const qEmb = await getEmbedding(query);
const scored = vectors.map(v => ({
...v,
score: cosineSimilarity(qEmb, v.embedding)
})).sort((a,b) => b.score - a.score).slice(0,k);
// Highlight in table + show topk
renderTopK(scored);
// Trigger rerank, etc.
return scored;
}
function renderTable() {
// Populate tbody with rows, add click handlers
}
// Chat handler: on submit -> search -> (rerank) -> context -> generate -> append to chat
// Init
window.onload = () => {
initModels();
// Tailwind script already loaded
};
</script>
</body>
</html>