Spaces:
Running
Running
<div class="typing"><span></span><span></span><span></span></div> and also the same error - Initial Deployment
1b748d5 verified | <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | |
| <title>Fullscreen AI Chatbot — Structured Output + Copy Code</title> | |
| <!-- Highlight.js styles --> | |
| <link rel="stylesheet" | |
| href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css"> | |
| <style> | |
| :root{ | |
| --bg: #0b1220; | |
| --panel: #0f1724; | |
| --muted: #98a0b3; | |
| --accent: #38bdf8; | |
| --card: #0b1228; | |
| --bot-bg: #0f1724; | |
| --user-bg: #0369a1; | |
| --text: #e6eef8; | |
| --radius: 12px; | |
| --glass: rgba(255,255,255,0.03); | |
| } | |
| *{box-sizing:border-box} | |
| html,body{height:100%; margin:0; font-family:Inter,ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial; background:var(--bg); color:var(--text);} | |
| /* Layout: full screen split - left conversation, right optional panel (hidden on small screens) */ | |
| .app { | |
| height:100vh; | |
| display:grid; | |
| grid-template-columns: 1fr 360px; | |
| gap:18px; | |
| padding:18px; | |
| } | |
| /* mobile: single column */ | |
| @media (max-width:980px){ | |
| .app { grid-template-columns: 1fr; padding:10px; } | |
| .sidebar{ display:none; } | |
| } | |
| /* chat column */ | |
| .chat-area { | |
| background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent); | |
| border-radius: var(--radius); | |
| padding: 14px; | |
| display:flex; | |
| flex-direction:column; | |
| min-width:0; | |
| box-shadow: 0 8px 30px rgba(2,6,23,0.6); | |
| border:1px solid rgba(255,255,255,0.03); | |
| overflow:hidden; | |
| } | |
| .topbar { | |
| display:flex; | |
| align-items:center; | |
| gap:12px; | |
| padding:8px 6px; | |
| border-bottom:1px solid rgba(255,255,255,0.03); | |
| } | |
| .logo { | |
| display:flex; | |
| align-items:center; | |
| gap:10px; | |
| font-weight:700; | |
| font-size:16px; | |
| } | |
| .logo .dot { width:10px; height:10px; border-radius:50%; background:var(--accent); box-shadow:0 0 12px var(--accent); } | |
| .controls { margin-left:auto; display:flex; gap:8px; align-items:center; color:var(--muted); } | |
| .clear-btn, .copy-convo-btn { | |
| background:transparent; | |
| border:1px solid rgba(255,255,255,0.03); | |
| color:var(--muted); | |
| padding:6px 10px; | |
| border-radius:8px; | |
| cursor:pointer; | |
| font-size:13px; | |
| } | |
| /* messages list */ | |
| .messages { | |
| flex:1; | |
| overflow:auto; | |
| padding:18px 8px; | |
| display:flex; | |
| flex-direction:column; | |
| gap:12px; | |
| } | |
| .msg { | |
| display:inline-block; | |
| max-width:85%; | |
| padding:12px 14px; | |
| border-radius:12px; | |
| line-height:1.45; | |
| white-space:pre-wrap; | |
| word-break:break-word; | |
| } | |
| .msg.user { | |
| align-self:flex-end; | |
| background:linear-gradient(180deg,var(--user-bg), #065f87); | |
| color: #fff; | |
| border-bottom-right-radius:6px; | |
| box-shadow: 0 6px 18px rgba(3,105,161,0.15); | |
| } | |
| .msg.bot { | |
| align-self:flex-start; | |
| background:var(--bot-bg); | |
| border:1px solid rgba(255,255,255,0.03); | |
| color:var(--text); | |
| border-bottom-left-radius:6px; | |
| } | |
| /* markdown inside bot messages */ | |
| .msg.bot h1, .msg.bot h2, .msg.bot h3 { | |
| color:var(--accent); margin:8px 0; | |
| } | |
| .msg.bot p { color: #dbe8f8; margin:6px 0; } | |
| .msg.bot ul, .msg.bot ol { margin:8px 0 8px 20px; color: #cfe9fb; } | |
| .msg.bot blockquote { border-left:3px solid rgba(56,189,248,0.18); padding-left:12px; color:#9fbfd8; margin:8px 0; font-style:italic; } | |
| .msg.bot table { border-collapse:collapse; width:100%; margin:8px 0; } | |
| .msg.bot th, .msg.bot td { border:1px solid rgba(255,255,255,0.04); padding:8px; text-align:left; } | |
| .msg.bot code.inline { background:rgba(255,255,255,0.03); padding:2px 6px; border-radius:6px; color:#9ff; font-family:monospace; } | |
| .msg.bot pre { background:#021022; border-radius:8px; padding:12px; overflow:auto; position:relative; margin:8px 0; } | |
| /* copy button for code blocks */ | |
| .code-copy { | |
| position:absolute; | |
| right:10px; top:10px; | |
| background:var(--accent); | |
| border:none; | |
| color:#00131b; | |
| padding:6px 9px; | |
| border-radius:8px; | |
| cursor:pointer; | |
| font-weight:600; | |
| font-size:12px; | |
| } | |
| /* input area */ | |
| .input-area { | |
| margin-top:12px; | |
| display:flex; | |
| gap:12px; | |
| align-items:center; | |
| padding:12px; | |
| border-radius:10px; | |
| background: linear-gradient(180deg, rgba(255,255,255,0.01), transparent); | |
| border:1px solid rgba(255,255,255,0.02); | |
| } | |
| .input-area textarea { | |
| flex:1; | |
| min-height:48px; | |
| max-height:160px; | |
| resize:none; | |
| padding:10px 12px; | |
| border-radius:10px; | |
| border:none; | |
| outline:none; | |
| font-size:15px; | |
| background:transparent; | |
| color:var(--text); | |
| } | |
| .send-row { display:flex; gap:8px; align-items:center; } | |
| .send-btn { | |
| background:var(--accent); | |
| border:none; | |
| color:#00131b; | |
| font-weight:700; | |
| padding:10px 14px; | |
| border-radius:10px; | |
| cursor:pointer; | |
| box-shadow:0 8px 24px rgba(56,189,248,0.12); | |
| font-size:15px; | |
| } | |
| .secondary { | |
| background:transparent; | |
| border:1px solid rgba(255,255,255,0.04); | |
| color:var(--muted); | |
| padding:8px 10px; | |
| border-radius:10px; | |
| cursor:pointer; | |
| font-size:13px; | |
| } | |
| /* right sidebar (instructions / system prompt / toggles) */ | |
| .sidebar { | |
| background:var(--panel); | |
| border-radius:12px; | |
| padding:12px; | |
| min-height:0; | |
| border:1px solid rgba(255,255,255,0.03); | |
| display:flex; | |
| flex-direction:column; | |
| gap:12px; | |
| } | |
| .sidebar h3 { color:var(--accent); margin:0; font-size:14px; } | |
| .sidebar textarea { | |
| width:100%; | |
| height:120px; | |
| resize:none; | |
| background:transparent; | |
| border:1px solid rgba(255,255,255,0.03); | |
| color:var(--text); | |
| padding:8px; | |
| border-radius:8px; | |
| font-size:13px; | |
| } | |
| .meta-row { display:flex; gap:8px; align-items:center; } | |
| .small { font-size:13px; color:var(--muted); } | |
| /* typing indicator style */ | |
| .typing { | |
| display: flex; | |
| gap: 8px; | |
| padding: 14px 16px; | |
| align-items: center; | |
| } | |
| .typing span { | |
| display: inline-block; | |
| width: 10px; | |
| height: 10px; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| animation: blink 1.4s infinite ease-in-out; | |
| opacity: 0.4; | |
| } | |
| .typing span:nth-child(1) { animation-delay: 0s } | |
| .typing span:nth-child(2) { animation-delay: 0.2s } | |
| .typing span:nth-child(3) { animation-delay: 0.4s } | |
| @keyframes blink { | |
| 0%, 100% { opacity: 0.2; transform: scale(0.8); } | |
| 50% { opacity: 1; transform: scale(1); } | |
| } | |
| /* small helper */ | |
| .muted { color:var(--muted); font-size:13px; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <!-- Chat area --> | |
| <div class="chat-area" role="main" aria-label="Chat area"> | |
| <div class="topbar"> | |
| <div class="logo"><span class="dot"></span> Super Chat</div> | |
| <div class="controls"> | |
| <button class="clear-btn" id="clearBtn" title="Clear conversation">Clear</button> | |
| <button class="copy-convo-btn" id="copyConvoBtn" title="Copy entire conversation">Copy convo</button> | |
| </div> | |
| </div> | |
| <div class="messages" id="messages" aria-live="polite"></div> | |
| <div style="margin-top:10px"></div> | |
| <div class="input-area" role="region" aria-label="Message input"> | |
| <textarea id="userInput" placeholder="Ask me anything... (Shift+Enter for newline). Use the sidebar to add system instructions." spellcheck="true"></textarea> | |
| <div class="send-row"> | |
| <button class="secondary" id="toggleSystemBtn" title="Toggle system prompt area">System</button> | |
| <button class="send-btn" id="sendBtn">Send</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Sidebar --> | |
| <aside class="sidebar" id="sidebar"> | |
| <div> | |
| <h3>System prompt</h3> | |
| <textarea id="systemPrompt">You are a helpful assistant. Provide structured, well-formatted responses. When returning code blocks, include language hints (e.g., ```js). Use headings, lists, tables where appropriate.</textarea> | |
| <div class="meta-row"> | |
| <button class="secondary" id="applySystemBtn">Apply</button> | |
| <button class="secondary" id="saveSystemBtn">Save</button> | |
| <div style="flex:1"></div> | |
| <div class="small">Model: <strong>cognitivecomputations/dolphin-mistral-24b-venice-edition:free</strong></div> | |
| </div> | |
| </div> | |
| <div> | |
| <h3>Settings</h3> | |
| <label class="small">Max tokens: <input type="number" id="maxTokens" value="1000" style="width:80px; margin-left:8px"></label> | |
| <div style="height:8px"></div> | |
| <label class="small">Temperature: <input type="number" id="temperature" value="0.2" step="0.1" min="0" max="1" style="width:60px; margin-left:6px"></label> | |
| </div> | |
| <div> | |
| <h3>Shortcuts</h3> | |
| <div class="small">Press <kbd>Enter</kbd> to send, <kbd>Shift+Enter</kbd> newline.</div> | |
| <div style="height:6px"></div> | |
| <div class="small">Click the copy button inside code blocks to copy the code.</div> | |
| </div> | |
| </aside> | |
| </div> | |
| <!-- Libraries --> | |
| <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script> | |
| <script>hljs.highlightAll();</script> | |
| <script> | |
| /********************************************************* | |
| * Fullscreen Chatbot — client-side demo | |
| * | |
| * IMPORTANT: This demo puts your API key directly in the | |
| * client. For production, proxy requests through a backend. | |
| *********************************************************/ | |
| // === Replace with your key (you provided it). Keep it secret in real apps. === | |
| const OPENROUTER_API_KEY = "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"; | |
| const API_URL = "https://openrouter.ai/api/v1/chat/completions"; | |
| const MODEL_NAME = "cognitivecomputations/dolphin-mistral-24b-venice-edition:free"; | |
| // UI elements | |
| const messagesEl = document.getElementById('messages'); | |
| const userInput = document.getElementById('userInput'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const clearBtn = document.getElementById('clearBtn'); | |
| const copyConvoBtn = document.getElementById('copyConvoBtn'); | |
| const sidebar = document.getElementById('sidebar'); | |
| const toggleSystemBtn = document.getElementById('toggleSystemBtn'); | |
| const systemPromptEl = document.getElementById('systemPrompt'); | |
| const applySystemBtn = document.getElementById('applySystemBtn'); | |
| const maxTokensEl = document.getElementById('maxTokens'); | |
| const temperatureEl = document.getElementById('temperature'); | |
| // conversation memory | |
| let conversation = []; | |
| // by default include system prompt if any | |
| let systemPrompt = systemPromptEl.value.trim(); | |
| if(systemPrompt) conversation.push({ role: "system", content: systemPrompt }); | |
| // Small helper to create elements | |
| function el(tag, props={}, ...children){ | |
| const d = document.createElement(tag); | |
| for(const k in props) { | |
| if(k === 'class') d.className = props[k]; | |
| else if(k === 'html') d.innerHTML = props[k]; | |
| else d.setAttribute(k, props[k]); | |
| } | |
| for(const c of children) if(typeof c === 'string') d.appendChild(document.createTextNode(c)); else d.appendChild(c); | |
| return d; | |
| } | |
| // Render a message (role: 'user' | 'assistant') | |
| function renderMessage(role, htmlContent, rawText) { | |
| const m = el('div', { class: 'msg ' + (role === 'user' ? 'user' : 'bot') }); | |
| // if assistant -> content is HTML (from marked) | |
| m.innerHTML = htmlContent; | |
| messagesEl.appendChild(m); | |
| messagesEl.scrollTop = messagesEl.scrollHeight; | |
| // After adding, find code blocks and add copy buttons & syntax highlight | |
| m.querySelectorAll('pre').forEach(pre => { | |
| // avoid adding multiple buttons | |
| if(pre.querySelector('.code-copy')) return; | |
| const lang = pre.getAttribute('data-lang') || 'code'; | |
| const btn = el('button', { class: 'code-copy' }, `Copy ${lang}`); | |
| pre.style.position = 'relative'; | |
| pre.prepend(btn); // place inside pre (left) — absolute will move it to top-right | |
| // fix absolute location: move btn outside text but top-right visually | |
| btn.style.position = 'absolute'; | |
| btn.style.right = '10px'; | |
| btn.style.top = '10px'; | |
| btn.addEventListener('click', async () => { | |
| // copy code text | |
| const codeEl = pre.querySelector('code'); | |
| const textToCopy = codeEl ? codeEl.innerText : pre.innerText; | |
| try{ | |
| await navigator.clipboard.writeText(textToCopy); | |
| btn.textContent = 'Copied!'; | |
| setTimeout(()=> btn.textContent = 'Copy', 1600); | |
| }catch(err){ | |
| btn.textContent = 'Copy'; | |
| } | |
| }); | |
| }); | |
| // run highlight.js on any code blocks inside this message | |
| m.querySelectorAll('pre code').forEach((block) => { | |
| try { hljs.highlightElement(block); } catch(e) { /* ignore */ } | |
| }); | |
| return m; | |
| } | |
| // Convert assistant content (markdown) to sanitized HTML with marked | |
| const markedRenderer = new marked.Renderer(); | |
| // Customize code rendering so we wrap language classes (highlight.js picks them) | |
| markedRenderer.code = function(code, infostring, escaped) { | |
| const lang = (infostring || '').match(/\S*/)[0]; | |
| const langClass = lang ? `language-${lang}` : ''; | |
| // Add data-lang attribute for the copy button | |
| return `<pre data-lang="${infostring || ''}"><code class="${langClass}">${escapeHtml(code)}</code></pre>`; | |
| }; | |
| marked.setOptions({ | |
| renderer: markedRenderer, | |
| breaks: true, | |
| gfm: true | |
| }); | |
| function escapeHtml(unsafe){ | |
| if (typeof unsafe !== 'string') return unsafe; | |
| return unsafe | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">"); | |
| } | |
| // Send message handler | |
| async function sendMessage() { | |
| const text = userInput.value.trim(); | |
| if(!text) return; | |
| // Add to UI (user) | |
| renderMessage('user', `<div>${escapeHtml(text)}</div>`, text); | |
| // add to conversation history | |
| conversation.push({ role: "user", content: text }); | |
| // clear input | |
| userInput.value = ''; | |
| // show typing placeholder from assistant | |
| const typingNode = el('div', { class: 'msg bot' }, `<div class="typing"><span></span><span></span><span></span></div>`); | |
| messagesEl.appendChild(typingNode); | |
| messagesEl.scrollTop = messagesEl.scrollHeight; | |
| // prepare payload | |
| const payload = { | |
| model: MODEL_NAME, | |
| messages: conversation, | |
| // pass settings from sidebar | |
| max_tokens: Number(maxTokensEl.value) || 1000, | |
| temperature: Number(temperatureEl.value) || 0.2 | |
| }; | |
| try { | |
| const res = await fetch(API_URL, { | |
| method: 'POST', | |
| headers: { | |
| "Content-Type": "application/json", | |
| "Authorization": `Bearer ${OPENROUTER_API_KEY}`, | |
| // optional headers that were used earlier | |
| "HTTP-Referer": window.location.origin, | |
| "X-Title": "Super Chat" | |
| }, | |
| body: JSON.stringify(payload) | |
| }); | |
| if(!res.ok){ | |
| const errText = await res.text(); | |
| throw new Error(`API error: ${res.status} ${errText}`); | |
| } | |
| const data = await res.json(); | |
| // remove typing node | |
| typingNode.remove(); | |
| // get assistant message content | |
| const assistantText = data?.choices?.[0]?.message?.content || "(no response)"; | |
| // push assistant to conversation | |
| conversation.push({ role: "assistant", content: assistantText }); | |
| // render assistant markdown | |
| const html = marked.parse(assistantText); | |
| renderMessage('assistant', html, assistantText); | |
| } catch (err) { | |
| // remove typing node if present | |
| typingNode.remove(); | |
| const errHtml = `<div><strong style="color:#ff7a7a">Error:</strong> ${escapeHtml(err.message)}</div>`; | |
| renderMessage('assistant', errHtml, err.message); | |
| } | |
| } | |
| // UI wiring | |
| sendBtn.addEventListener('click', sendMessage); | |
| userInput.addEventListener('keydown', (e) => { | |
| if(e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| clearBtn.addEventListener('click', () => { | |
| if(!confirm('Clear conversation?')) return; | |
| conversation = []; | |
| // re-add system prompt if present | |
| systemPrompt = systemPromptEl.value.trim(); | |
| if(systemPrompt) conversation.push({ role: "system", content: systemPrompt }); | |
| messagesEl.innerHTML = ''; | |
| userInput.focus(); | |
| }); | |
| copyConvoBtn.addEventListener('click', async () => { | |
| const text = conversation.map(m => `${m.role.toUpperCase()}: ${m.content}`).join('\n\n'); | |
| try { | |
| await navigator.clipboard.writeText(text); | |
| copyConvoBtn.textContent = 'Copied!'; | |
| setTimeout(()=> copyConvoBtn.textContent = 'Copy convo', 1400); | |
| } catch { | |
| alert('Copy failed — please allow clipboard permission.'); | |
| } | |
| }); | |
| toggleSystemBtn.addEventListener('click', () => { | |
| sidebar.style.display = sidebar.style.display === 'none' ? 'flex' : 'flex'; | |
| // on small screens, toggle visibility | |
| if(window.innerWidth < 980){ | |
| sidebar.style.display = sidebar.style.display === 'none' ? 'flex' : (sidebar.style.display === 'flex' ? 'none' : 'flex'); | |
| } | |
| }); | |
| applySystemBtn.addEventListener('click', () => { | |
| systemPrompt = systemPromptEl.value.trim(); | |
| // remove old system messages from conversation | |
| conversation = conversation.filter(m => m.role !== 'system'); | |
| if(systemPrompt) conversation.unshift({ role: "system", content: systemPrompt }); | |
| alert('Applied system prompt to conversation. (It will be sent on next request.)'); | |
| }); | |
| // load saved system prompt if any (localStorage optional) | |
| try { | |
| const saved = localStorage.getItem('superchat_system'); | |
| if(saved) systemPromptEl.value = saved; | |
| document.getElementById('saveSystemBtn').addEventListener('click', () => { | |
| localStorage.setItem('superchat_system', systemPromptEl.value); | |
| alert('System prompt saved locally.'); | |
| }); | |
| } catch(e){ /* ignore localStorage errors */ } | |
| // initial focus | |
| userInput.focus(); | |
| // helpful dev message (optional) | |
| // renderMessage('assistant', marked.parse('Hello! I am ready. Send a message and I will reply with structured & formatted output.')); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Murugesaninyt/super-chat" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> | |