Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Nova-2-Nano — Pure NTA Think Twice</title> | |
| <style> | |
| :root { --cyan: #00FFFF; --pink: #FF69B4; --dark: #0a0a0f; --card: #12121a; --border: #1e1e2e; --text: #e0e0e0; --muted: #888; } | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: 'Inter', sans-serif; background: var(--dark); color: var(--text); min-height: 100vh; } | |
| .bg-glow { position: fixed; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle at 30% 40%, rgba(0,255,255,0.03) 0%, transparent 50%), radial-gradient(circle at 70% 60%, rgba(255,105,180,0.03) 0%, transparent 50%); animation: pulse 8s ease-in-out infinite; z-index: -1; } | |
| @keyframes pulse { 0%, 100% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.1); opacity: 0.8; } } | |
| .container { max-width: 900px; margin: 0 auto; padding: 2rem 1rem; } | |
| header { text-align: center; margin-bottom: 2rem; } | |
| .logo { font-size: 2.5rem; font-weight: 800; background: linear-gradient(135deg, var(--cyan), var(--pink)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } | |
| .subtitle { color: var(--muted); font-family: monospace; font-size: 0.9rem; letter-spacing: 2px; } | |
| .chat-container { background: var(--card); border: 1px solid var(--border); border-radius: 16px; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.5); } | |
| .messages { height: 500px; overflow-y: auto; padding: 1.5rem; display: flex; flex-direction: column; gap: 1rem; } | |
| .message { max-width: 95%; padding: 1rem; border-radius: 12px; line-height: 1.6; animation: fadeIn 0.3s ease; background: rgba(0,0,0,0.2); border: 1px solid var(--border); } | |
| @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } | |
| pre { white-space: pre-wrap; font-family: 'JetBrains Mono', monospace; margin: 0; font-size: 0.95rem; } | |
| .prompt-text { color: var(--cyan); } | |
| .gen-text { color: var(--text); } | |
| .message-meta { font-size: 0.75rem; color: var(--muted); margin-top: 0.75rem; font-family: monospace; border-top: 1px solid var(--border); padding-top: 0.5rem; } | |
| .confidence-bar { height: 3px; background: var(--border); border-radius: 2px; margin-top: 0.5rem; overflow: hidden; } | |
| .confidence-fill { height: 100%; background: linear-gradient(90deg, var(--cyan), var(--pink)); transition: width 0.5s ease; } | |
| .input-area { padding: 1rem 1.5rem; border-top: 1px solid var(--border); display: flex; gap: 0.75rem; align-items: flex-end; } | |
| textarea { flex: 1; background: var(--dark); border: 1px solid var(--border); border-radius: 12px; padding: 0.75rem 1rem; color: var(--text); font-family: 'JetBrains Mono', monospace; font-size: 0.95rem; resize: none; min-height: 80px; outline: none; } | |
| textarea:focus { border-color: var(--cyan); } | |
| button.send { background: linear-gradient(135deg, var(--cyan), var(--pink)); border: none; border-radius: 12px; padding: 0.75rem 1.5rem; color: var(--dark); font-weight: 700; cursor: pointer; height: 48px; } | |
| button.send:disabled { opacity: 0.5; cursor: not-allowed; } | |
| .controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 1rem; padding: 1rem 1.5rem; border-top: 1px solid var(--border); background: rgba(0,0,0,0.2); } | |
| .control-group label { display: block; font-size: 0.75rem; color: var(--muted); margin-bottom: 0.25rem; text-transform: uppercase; } | |
| select, input[type="range"] { width: 100%; background: var(--dark); border: 1px solid var(--border); border-radius: 8px; padding: 0.5rem; color: var(--text); } | |
| .toggle { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; } | |
| .toggle input { accent-color: var(--cyan); width: 16px; height: 16px; } | |
| .status-bar { display: flex; justify-content: space-between; padding: 0.75rem 1.5rem; background: rgba(0,0,0,0.3); font-family: monospace; font-size: 0.8rem; color: var(--muted); } | |
| .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #4ade80; display: inline-block; margin-right: 0.5rem; animation: blink 2s infinite; } | |
| @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } | |
| .arch-badge { display: inline-block; background: rgba(0,255,255,0.1); border: 1px solid var(--cyan); border-radius: 6px; padding: 0.25rem 0.5rem; font-size: 0.7rem; color: var(--cyan); margin-top: 0.5rem; font-family: monospace; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bg-glow"></div> | |
| <div class="container"> | |
| <header> | |
| <div class="logo">🧠 Nova-2-Nano</div> | |
| <div class="subtitle">PURE NTA • 304M PARAMS • THINK TWICE</div> | |
| <div class="arch-badge">12x NovaTripleAttention | 1024-d | PPL 1.0</div> | |
| </header> | |
| <div class="chat-container"> | |
| <div class="messages" id="messages"> | |
| <div class="message"> | |
| <pre><span class="prompt-text">Nova-2-Nano is ready. Pure NTA architecture with internal ThinkTwice.</span></pre> | |
| <div class="message-meta">Type a prompt below. Toggle ThinkTwice to see per-layer confidence re-computation.</div> | |
| </div> | |
| </div> | |
| <div class="controls"> | |
| <div class="control-group"> | |
| <label>Max Tokens: <span id="maxTokensVal">150</span></label> | |
| <input type="range" id="maxTokens" min="10" max="512" value="150" step="10"> | |
| </div> | |
| <div class="control-group"> | |
| <label>Temp: <span id="tempVal">0.7</span></label> | |
| <input type="range" id="temperature" min="0.1" max="1.5" value="0.7" step="0.1"> | |
| </div> | |
| <div class="control-group"> | |
| <label>Think Twice</label> | |
| <div class="toggle"> | |
| <input type="checkbox" id="thinkTwice" checked> | |
| <span>Per-Layer</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="input-area"> | |
| <textarea id="input" placeholder="Type your prompt here...">def reverse_string(s): | |
| return </textarea> | |
| <button class="send" id="sendBtn">Generate 🚀</button> | |
| </div> | |
| <div class="status-bar"> | |
| <span><span class="status-dot"></span><span id="statusText">Connected</span></span> | |
| <span id="statsText">Triggers: — | Conf: —</span> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| const API_BASE = window.location.origin; | |
| const messagesEl = document.getElementById('messages'); | |
| const inputEl = document.getElementById('input'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const statusText = document.getElementById('statusText'); | |
| const statsText = document.getElementById('statsText'); | |
| inputEl.addEventListener('input', () => { | |
| inputEl.style.height = 'auto'; | |
| inputEl.style.height = Math.min(inputEl.scrollHeight, 200) + 'px'; | |
| }); | |
| document.getElementById('maxTokens').addEventListener('input', e => document.getElementById('maxTokensVal').textContent = e.target.value); | |
| document.getElementById('temperature').addEventListener('input', e => document.getElementById('tempVal').textContent = e.target.value); | |
| async function sendMessage() { | |
| const text = inputEl.value; | |
| if (!text) return; | |
| inputEl.value = ''; | |
| inputEl.style.height = 'auto'; | |
| sendBtn.disabled = true; | |
| statusText.textContent = 'Generating...'; | |
| const outputDiv = document.createElement('div'); | |
| outputDiv.className = 'message'; | |
| const safePrompt = text.replace(/</g, "<").replace(/>/g, ">"); | |
| outputDiv.innerHTML = `<pre><span class="prompt-text">${safePrompt}</span><span class="gen-text"></span></pre><div class="message-meta" id="live-stats">🧠 Generating...</div>`; | |
| messagesEl.appendChild(outputDiv); | |
| messagesEl.scrollTop = messagesEl.scrollHeight; | |
| const genTextEl = outputDiv.querySelector('.gen-text'); | |
| const statsEl = outputDiv.querySelector('#live-stats'); | |
| let fullText = ""; | |
| try { | |
| const response = await fetch(`${API_BASE}/v1/completions/stream`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| prompt: text, | |
| max_tokens: parseInt(document.getElementById('maxTokens').value), | |
| temperature: parseFloat(document.getElementById('temperature').value), | |
| think_twice: document.getElementById('thinkTwice').checked | |
| }) | |
| }); | |
| const reader = response.body.getReader(); | |
| const decoder = new TextDecoder(); | |
| let buffer = ""; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| buffer += decoder.decode(value, { stream: true }); | |
| const lines = buffer.split('\n'); | |
| buffer = lines.pop(); | |
| for (const line of lines) { | |
| if (line.startsWith('event:')) { | |
| var eventType = line.replace('event:', '').trim(); | |
| } else if (line.startsWith('data:')) { | |
| const dataStr = line.replace('data:', '').trim(); | |
| if (!dataStr) continue; | |
| try { | |
| const data = JSON.parse(dataStr); | |
| if (eventType === 'token') { | |
| fullText += data.text; | |
| genTextEl.innerHTML = fullText.replace(/</g, "<").replace(/>/g, ">"); | |
| messagesEl.scrollTop = messagesEl.scrollHeight; | |
| } else if (eventType === 'thinking') { | |
| statsEl.innerHTML = `🧠 Re-computing... (Layer Conf: ${(data.avg_layer_conf * 100).toFixed(0)}%)`; | |
| statsEl.style.color = 'var(--pink)'; | |
| } else if (eventType === 'done') { | |
| statsEl.innerHTML = `🧠 ThinkTwice Triggers: ${data.think_twice_triggers} | Conf: ${(data.final_confidence * 100).toFixed(0)}% | ${data.latency_ms.toFixed(0)}ms`; | |
| statsEl.style.color = 'var(--muted)'; | |
| statsText.textContent = `Triggers: ${data.think_twice_triggers} | Conf: ${(data.final_confidence * 100).toFixed(0)}%`; | |
| const bar = document.createElement('div'); | |
| bar.className = 'confidence-bar'; | |
| const fill = document.createElement('div'); | |
| fill.className = 'confidence-fill'; | |
| fill.style.width = `${Math.round(data.final_confidence * 100)}%`; | |
| bar.appendChild(fill); | |
| outputDiv.appendChild(bar); | |
| } | |
| } catch (e) { console.error(e); } | |
| } | |
| } | |
| } | |
| statusText.textContent = 'Ready'; | |
| } catch (err) { | |
| genTextEl.innerHTML += `<br>❌ Error: ${err.message}`; | |
| statusText.textContent = 'Error'; | |
| } finally { | |
| sendBtn.disabled = false; | |
| inputEl.focus(); | |
| } | |
| } | |
| sendBtn.addEventListener('click', sendMessage); | |
| inputEl.addEventListener('keydown', e => { | |
| if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| fetch(`${API_BASE}/health`).then(r => r.json()).then(d => statusText.textContent = d.model_loaded ? 'Model Loaded ✅' : 'Loading...').catch(() => statusText.textContent = 'Disconnected ❌'); | |
| </script> | |
| </body> | |
| </html> |