hugging2021/local-gemma4-rag
1
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Gemma 4 | Private Local RAG</title>7 <link rel="preconnect" href="https://fonts.googleapis.com">8 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>9 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;800&display=swap" rel="stylesheet">10 <link rel="stylesheet" href="style.css">11 <!-- Essential Libraries -->12 <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>13 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/github-dark.min.css">14 <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>15 <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script>16 <script>17 // Set worker for pdf.js18 pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js';19 20 // Configure marked with highlight.js21 window.marked.setOptions({22 highlight: function(code, lang) {23 if (lang && hljs.getLanguage(lang)) {24 return hljs.highlight(code, { language: lang }).value;25 }26 return hljs.highlightAuto(code).value;27 },28 gfm: true,29 breaks: true30 });31 </script>32</head>33<body>34 <div class="container">35 <header>36 <div class="header-content">37 <h1>Gemma 4 RAG</h1>38 <p class="subtitle">Secure, local-first document chat powered by WebGPU & Orama</p>39 </div>40 <div id="sync-indicator" title="Synchronized with GitHub & HF">41 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>42 </div>43 </header>44 45 <main id="app">46 <!-- Setup & Initialization -->47 <div id="setup-container" class="card glass">48 <div class="status-box">49 <h2 id="status-text">Initialize AI Engine</h2>50 <p class="status-label">Ready to load ~1.6GB of optimized models to your GPU</p>51 </div>52 53 <div class="status-grid">54 <div class="status-item" id="status-embedding">55 <div class="status-label">Embedding (MiniLM-L6)</div>56 <div class="progress-bar-container">57 <div id="progress-embedding" class="progress-fill"></div>58 </div>59 </div>60 <div class="status-item" id="status-llm">61 <div class="status-label">Gemma 4 (Q4_K_M)</div>62 <div class="progress-bar-container">63 <div id="progress-llm" class="progress-fill"></div>64 </div>65 </div>66 </div>67 68 <div class="model-selector-container">69 <label for="model-select" class="status-label">Select Model Variant:</label>70 <select id="model-select" class="glass-select">71 <option value="onnx-community/gemma-4-E2B-it-ONNX">Gemma 4 E2B (2B - Fast, Recommended)</option>72 <option value="onnx-community/gemma-4-E4B-it-ONNX">Gemma 4 E4B (4B - High Quality, needs 6GB+ VRAM)</option>73 </select>74 <p class="hint" style="margin-top: 0.5rem; text-align: center;">4B variant requires significant GPU memory (~4GB download).</p>75 </div>76 77 <button id="init-btn" class="primary-btn">Initialize WebGPU AI</button>78 <p id="error-message" class="error-text" style="display: none;"></p>79 </div>80 81 <!-- Chat & Upload Interface (Initially Hidden) -->82 <div id="chat-container" class="hidden">83 <!-- Sidebar: Indexed Documents -->84 <aside id="sidebar" class="card glass">85 <h3>Indexed Documents</h3>86 <div id="docs-list-container">87 <ul id="docs-list">88 <p class="hint">No documents indexed yet.</p>89 </ul>90 </div>91 </aside>92 93 <div class="chat-main">94 <!-- Upload Section -->95 <div class="card glass" id="upload-card">96 <div class="upload-btn-wrapper">97 <div class="upload-btn-placeholder">98 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>99 <p id="upload-status">Drop files here or click to index documents</p>100 <p class="hint">Supports TXT, MD, PDF (local parsing)</p>101 </div>102 <input type="file" id="file-input" multiple accept=".txt,.md,.pdf,.js" />103 </div>104 </div>105 106 <!-- Chat History -->107 <div class="card glass chat-card">108 <div class="chat-header">109 <h3>Conversation</h3>110 <button id="clear-chat-btn" title="Clear conversation history">🗑️ Clear Chat</button>111 </div>112 <div id="chat-history">113 <div class="message ai">114 <div class="avatar">G4</div>115 <div class="content">116 Hello! I am initialized and ready. Upload some documents to start our private conversation.117 </div>118 </div>119 </div>120 121 <div class="input-area">122 <input type="text" id="user-input" placeholder="Ask a question about your documents..." autocomplete="off">123 <button id="send-btn">124 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>125 </button>126 </div>127 </div>128 </div>129 </div>130 </main>131 132 <footer>133 <div class="footer-content">134 <p>Created by <strong>Norberto Martín Afonso</strong> • Follow on 135 <a href="https://x.com/NorbertoMartnAf" target="_blank" class="social-link">X (@NorbertoMartnAf)</a> & 136 <a href="https://github.com/nmarafo" target="_blank" class="social-link">GitHub (nmarafo)</a>137 </p>138 <p class="tech-stack">Powered by <strong>Transformers.js v4</strong> & <strong>Orama v2</strong> • Local & Private</p>139 </div>140 </footer>141 </div>142 143 <!-- Scripts -->144 <script type="module" src="main.js"></script>145</body>146</html>