Spaces:
Running on Zero
Running on Zero
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Qwopus</title> | |
| <meta name="description" content="Qwopus by jackrong"> | |
| <!-- Fonts --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> | |
| <!-- FontAwesome --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <!-- Prism.js (light theme for Claude-style) --> | |
| <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet"> | |
| <!-- marked.js --> | |
| <script src="https://cdn.jsdelivr.net/npm/marked@9.1.6/marked.min.js"></script> | |
| <!-- Prism.js core + languages --> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-python.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-javascript.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-bash.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-cpp.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-java.min.js"></script> | |
| <!-- MathJax --> | |
| <script> | |
| window.MathJax = { | |
| tex: { | |
| inlineMath: [['$', '$'], ['\\(', '\\)']], | |
| displayMath: [['$$', '$$'], ['\\[', '\\]']], | |
| processEscapes: true | |
| }, | |
| options: { skipHtmlTags: ['script','noscript','style','textarea','pre','code'] } | |
| }; | |
| </script> | |
| <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> | |
| <style> | |
| /* βββ Design Tokens βββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| :root { | |
| /* WeiboAI brand colors extracted from hummingbird logo */ | |
| --brand-deep: #C0310A; /* deep crimson-red */ | |
| --brand-mid: #E04015; /* primary orange-red */ | |
| --brand-bright: #F26027; /* vivid orange */ | |
| --brand-light: #F5874F; /* soft orange */ | |
| --brand-pale: #FEF0EB; /* blush tint */ | |
| /* Claude-style neutrals */ | |
| --bg: #FFFFFF; | |
| --bg-sidebar: #F7F6F3; | |
| --bg-hover: #EFEDE8; | |
| --bg-input: #F9F8F6; | |
| --border: #E8E6E1; | |
| --border-light: #F0EEE9; | |
| --text-primary: #1A1A18; | |
| --text-secondary:#6B6560; | |
| --text-muted: #9B9590; | |
| --text-on-brand: #FFFFFF; | |
| /* Shadows */ | |
| --shadow-sm: 0 1px 3px rgba(0,0,0,0.06); | |
| --shadow-md: 0 4px 12px rgba(0,0,0,0.08); | |
| --shadow-lg: 0 8px 24px rgba(0,0,0,0.10); | |
| --sidebar-w: 260px; | |
| --radius: 12px; | |
| --radius-sm: 8px; | |
| --radius-xs: 6px; | |
| } | |
| /* βββ Reset βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| html, body { | |
| height: 100%; | |
| font-family: 'Inter', system-ui, sans-serif; | |
| font-size: 15px; | |
| color: var(--text-primary); | |
| background: var(--bg); | |
| -webkit-font-smoothing: antialiased; | |
| } | |
| /* βββ Layout βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .app { | |
| display: flex; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| /* βββ Sidebar ββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .sidebar { | |
| width: var(--sidebar-w); | |
| background: var(--bg-sidebar); | |
| border-right: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| flex-shrink: 0; | |
| overflow: hidden; | |
| transition: width 0.22s ease; | |
| } | |
| .sidebar.collapsed { width: 0; border-right: none; } | |
| /* Brand / Logo area */ | |
| .sidebar-header { | |
| padding: 20px 16px 14px; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .brand-logo { | |
| width: 34px; | |
| height: 34px; | |
| border-radius: 8px; | |
| object-fit: cover; | |
| flex-shrink: 0; | |
| } | |
| .brand-name { | |
| font-size: 15px; | |
| font-weight: 700; | |
| color: var(--text-primary); | |
| letter-spacing: -0.3px; | |
| } | |
| .brand-tag { | |
| display: inline-block; | |
| font-size: 10px; | |
| font-weight: 600; | |
| background: var(--brand-pale); | |
| color: var(--brand-mid); | |
| border: 1px solid rgba(224,64,21,0.2); | |
| padding: 1px 6px; | |
| border-radius: 20px; | |
| letter-spacing: 0.2px; | |
| } | |
| /* Sidebar body / sections */ | |
| .sidebar-body { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 12px 10px; | |
| } | |
| .sidebar-body::-webkit-scrollbar { width: 4px; } | |
| .sidebar-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } | |
| .sidebar-section-label { | |
| font-size: 11px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.8px; | |
| color: var(--text-muted); | |
| padding: 8px 6px 6px; | |
| } | |
| /* Parameter controls */ | |
| .param-group { margin-bottom: 14px; padding: 0 4px; } | |
| .param-row { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 5px; | |
| } | |
| .param-label { font-size: 12.5px; color: var(--text-secondary); font-weight: 500; } | |
| .param-val { | |
| font-size: 12px; | |
| font-weight: 600; | |
| color: var(--brand-mid); | |
| min-width: 36px; | |
| text-align: right; | |
| } | |
| input[type="range"] { | |
| width: 100%; | |
| height: 4px; | |
| background: var(--border); | |
| border-radius: 2px; | |
| outline: none; | |
| -webkit-appearance: none; | |
| cursor: pointer; | |
| } | |
| input[type="range"]::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 14px; | |
| height: 14px; | |
| border-radius: 50%; | |
| background: var(--brand-mid); | |
| box-shadow: 0 0 0 3px rgba(224,64,21,0.15); | |
| transition: transform 0.1s; | |
| } | |
| input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.15); } | |
| .system-prompt-textarea { | |
| width: 100%; | |
| background: var(--bg); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-xs); | |
| color: var(--text-primary); | |
| font-family: inherit; | |
| font-size: 12px; | |
| line-height: 1.5; | |
| padding: 8px 10px; | |
| resize: vertical; | |
| min-height: 74px; | |
| outline: none; | |
| transition: border-color 0.15s; | |
| } | |
| .system-prompt-textarea:focus { border-color: var(--brand-light); } | |
| /* Preset buttons */ | |
| .preset-btn { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| width: 100%; | |
| padding: 8px 10px; | |
| border-radius: var(--radius-xs); | |
| border: none; | |
| background: transparent; | |
| color: var(--text-secondary); | |
| font-size: 12.5px; | |
| font-family: inherit; | |
| cursor: pointer; | |
| text-align: left; | |
| transition: background 0.12s, color 0.12s; | |
| } | |
| .preset-btn:hover { background: var(--bg-hover); color: var(--text-primary); } | |
| .preset-btn .preset-icon { | |
| width: 22px; height: 22px; | |
| background: var(--brand-pale); | |
| border-radius: 5px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 11px; | |
| color: var(--brand-mid); | |
| flex-shrink: 0; | |
| } | |
| .sidebar-footer { | |
| padding: 12px 14px; | |
| border-top: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 6px; | |
| } | |
| .footer-link { | |
| display: flex; | |
| align-items: center; | |
| gap: 7px; | |
| font-size: 12px; | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| padding: 4px 2px; | |
| border-radius: 4px; | |
| transition: color 0.12s; | |
| } | |
| .footer-link:hover { color: var(--brand-mid); } | |
| .footer-link i { width: 14px; text-align: center; } | |
| /* βββ Main Panel βββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .main { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 0; | |
| background: var(--bg); | |
| } | |
| /* Top bar */ | |
| .topbar { | |
| height: 56px; | |
| border-bottom: 1px solid var(--border); | |
| padding: 0 20px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| flex-shrink: 0; | |
| background: var(--bg); | |
| } | |
| .topbar-left { display: flex; align-items: center; gap: 12px; } | |
| .toggle-sidebar-btn { | |
| width: 32px; height: 32px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-xs); | |
| background: transparent; | |
| color: var(--text-secondary); | |
| display: flex; align-items: center; justify-content: center; | |
| cursor: pointer; | |
| font-size: 14px; | |
| transition: background 0.12s, color 0.12s, border-color 0.12s; | |
| } | |
| .toggle-sidebar-btn:hover { | |
| background: var(--bg-hover); | |
| color: var(--text-primary); | |
| border-color: var(--border); | |
| } | |
| .model-pill { | |
| display: flex; | |
| align-items: center; | |
| gap: 7px; | |
| padding: 5px 11px; | |
| border: 1px solid var(--border); | |
| border-radius: 20px; | |
| background: var(--bg); | |
| font-size: 13px; | |
| font-weight: 500; | |
| color: var(--text-primary); | |
| cursor: default; | |
| } | |
| .model-dot { | |
| width: 7px; height: 7px; | |
| border-radius: 50%; | |
| background: var(--brand-mid); | |
| flex-shrink: 0; | |
| } | |
| .model-dot.busy { | |
| animation: pulse-dot 1.2s ease-in-out infinite; | |
| } | |
| @keyframes pulse-dot { | |
| 0%, 100% { opacity: 1; transform: scale(1); } | |
| 50% { opacity: 0.4; transform: scale(0.7); } | |
| } | |
| .topbar-right { display: flex; align-items: center; gap: 8px; } | |
| .topbar-action-btn { | |
| width: 32px; height: 32px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-xs); | |
| background: transparent; | |
| color: var(--text-secondary); | |
| display: flex; align-items: center; justify-content: center; | |
| cursor: pointer; | |
| font-size: 13px; | |
| transition: background 0.12s, color 0.12s; | |
| text-decoration: none; | |
| } | |
| .topbar-action-btn:hover { background: var(--bg-hover); color: var(--text-primary); } | |
| /* βββ Chat area ββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .chat-scroll { | |
| flex: 1; | |
| overflow-y: auto; | |
| scroll-behavior: smooth; | |
| } | |
| .chat-scroll::-webkit-scrollbar { width: 5px; } | |
| .chat-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } | |
| .chat-inner { | |
| max-width: 740px; | |
| margin: 0 auto; | |
| padding: 32px 24px 16px; | |
| } | |
| /* βββ Welcome screen βββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .welcome { | |
| padding: 48px 0 32px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| text-align: center; | |
| gap: 20px; | |
| } | |
| .welcome-logo { | |
| width: 64px; | |
| height: 64px; | |
| border-radius: 16px; | |
| object-fit: cover; | |
| box-shadow: var(--shadow-md); | |
| } | |
| .welcome-title { | |
| font-size: 26px; | |
| font-weight: 700; | |
| letter-spacing: -0.5px; | |
| color: var(--text-primary); | |
| } | |
| .welcome-sub { | |
| font-size: 14.5px; | |
| color: var(--text-secondary); | |
| max-width: 520px; | |
| line-height: 1.65; | |
| } | |
| .welcome-chips { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| justify-content: center; | |
| margin-top: 4px; | |
| } | |
| .chip { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 7px 13px; | |
| border: 1px solid var(--border); | |
| border-radius: 20px; | |
| font-size: 13px; | |
| color: var(--text-secondary); | |
| background: var(--bg); | |
| cursor: pointer; | |
| transition: all 0.14s; | |
| } | |
| .chip:hover { | |
| border-color: var(--brand-light); | |
| color: var(--brand-mid); | |
| background: var(--brand-pale); | |
| } | |
| .chip i { font-size: 12px; } | |
| .welcome-cards { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 12px; | |
| width: 100%; | |
| margin-top: 8px; | |
| } | |
| .welcome-card { | |
| padding: 16px; | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| background: var(--bg); | |
| text-align: left; | |
| transition: border-color 0.14s, box-shadow 0.14s; | |
| } | |
| .welcome-card:hover { border-color: var(--brand-light); box-shadow: var(--shadow-sm); } | |
| .wc-icon { | |
| width: 28px; height: 28px; | |
| background: var(--brand-pale); | |
| border-radius: 7px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 13px; | |
| color: var(--brand-mid); | |
| margin-bottom: 10px; | |
| } | |
| .wc-title { font-size: 13px; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; } | |
| .wc-desc { font-size: 12px; color: var(--text-muted); line-height: 1.5; } | |
| /* βββ Messages βββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .message-group { | |
| margin-bottom: 24px; | |
| } | |
| /* User message */ | |
| .user-row { | |
| display: flex; | |
| justify-content: flex-end; | |
| margin-bottom: 4px; | |
| } | |
| .user-bubble { | |
| max-width: 72%; | |
| background: var(--brand-pale); | |
| border: 1px solid rgba(224,64,21,0.12); | |
| border-radius: 18px 18px 4px 18px; | |
| padding: 11px 16px; | |
| font-size: 14.5px; | |
| line-height: 1.6; | |
| color: var(--text-primary); | |
| word-wrap: break-word; | |
| } | |
| /* Assistant message */ | |
| .assistant-row { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| } | |
| .assistant-avatar { | |
| width: 28px; | |
| height: 28px; | |
| border-radius: 7px; | |
| object-fit: cover; | |
| flex-shrink: 0; | |
| margin-top: 2px; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .assistant-content { flex: 1; min-width: 0; } | |
| .assistant-name { | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-secondary); | |
| margin-bottom: 6px; | |
| } | |
| /* Thinking accordion */ | |
| .think-box { | |
| border: 1px solid #F0C4B4; | |
| border-radius: var(--radius-sm); | |
| background: #FFF7F4; | |
| margin-bottom: 12px; | |
| overflow: hidden; | |
| } | |
| .think-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 9px 13px; | |
| cursor: pointer; | |
| user-select: none; | |
| gap: 8px; | |
| } | |
| .think-header:hover { background: rgba(224,64,21,0.04); } | |
| .think-header-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 7px; | |
| font-size: 12.5px; | |
| font-weight: 600; | |
| color: var(--brand-mid); | |
| } | |
| .think-spinner { | |
| font-size: 11px; | |
| color: var(--brand-mid); | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { to { transform: rotate(360deg); } } | |
| .think-check { color: #22A757; font-size: 13px; } | |
| .think-timer { | |
| font-size: 11px; | |
| color: var(--text-muted); | |
| font-weight: 400; | |
| } | |
| .think-body { | |
| padding: 10px 13px 12px; | |
| border-top: 1px solid #F0C4B4; | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 12px; | |
| line-height: 1.65; | |
| color: #7A5040; | |
| white-space: pre-wrap; | |
| max-height: 220px; | |
| overflow-y: auto; | |
| background: #FFFAF8; | |
| } | |
| /* Response body markdown */ | |
| .response-body { | |
| font-size: 14.5px; | |
| line-height: 1.7; | |
| color: var(--text-primary); | |
| } | |
| .response-body p { margin-bottom: 10px; } | |
| .response-body p:last-child { margin-bottom: 0; } | |
| .response-body h1, .response-body h2, .response-body h3 { | |
| font-weight: 600; | |
| margin-top: 18px; | |
| margin-bottom: 6px; | |
| color: var(--text-primary); | |
| } | |
| .response-body h1 { font-size: 18px; } | |
| .response-body h2 { font-size: 16px; } | |
| .response-body h3 { font-size: 14.5px; } | |
| .response-body ul, .response-body ol { | |
| padding-left: 20px; | |
| margin-bottom: 10px; | |
| } | |
| .response-body li { margin-bottom: 3px; } | |
| .response-body strong { font-weight: 600; } | |
| .response-body em { font-style: italic; } | |
| .response-body code { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 12.5px; | |
| background: #F4F3F0; | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| padding: 1px 5px; | |
| } | |
| .response-body pre { | |
| margin: 12px 0; | |
| border-radius: var(--radius-sm); | |
| overflow: hidden; | |
| border: 1px solid var(--border); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .response-body pre code { | |
| background: none; | |
| border: none; | |
| padding: 0; | |
| font-size: 13px; | |
| border-radius: 0; | |
| } | |
| .response-body table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin: 12px 0; | |
| font-size: 13.5px; | |
| } | |
| .response-body th, .response-body td { | |
| border: 1px solid var(--border); | |
| padding: 7px 11px; | |
| text-align: left; | |
| } | |
| .response-body th { | |
| background: var(--bg-sidebar); | |
| font-weight: 600; | |
| } | |
| /* Code block header */ | |
| .code-block-wrap { position: relative; } | |
| .code-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 6px 12px; | |
| background: #F4F3F0; | |
| border-bottom: 1px solid var(--border); | |
| font-size: 11.5px; | |
| color: var(--text-muted); | |
| font-family: 'JetBrains Mono', monospace; | |
| } | |
| .code-copy-btn { | |
| background: none; | |
| border: none; | |
| color: var(--text-muted); | |
| cursor: pointer; | |
| font-size: 11.5px; | |
| display: flex; align-items: center; gap: 4px; | |
| padding: 2px 6px; | |
| border-radius: 4px; | |
| transition: background 0.12s, color 0.12s; | |
| } | |
| .code-copy-btn:hover { background: var(--border); color: var(--text-primary); } | |
| /* Typing dots */ | |
| .typing { display: flex; gap: 4px; padding: 4px 0; } | |
| .typing-dot { | |
| width: 7px; height: 7px; | |
| background: var(--brand-light); | |
| border-radius: 50%; | |
| animation: bounce-dot 1.3s ease-in-out infinite both; | |
| } | |
| .typing-dot:nth-child(1) { animation-delay: -0.3s; } | |
| .typing-dot:nth-child(2) { animation-delay: -0.15s; } | |
| @keyframes bounce-dot { | |
| 0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; } | |
| 40% { transform: scale(1); opacity: 1; } | |
| } | |
| /* βββ Input area βββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .input-area { | |
| padding: 16px 24px 24px; | |
| flex-shrink: 0; | |
| background: var(--bg); | |
| } | |
| .input-inner { | |
| max-width: 740px; | |
| margin: 0 auto; | |
| } | |
| .input-box { | |
| border: 1.5px solid var(--border); | |
| border-radius: 14px; | |
| background: var(--bg-input); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0; | |
| transition: border-color 0.15s, box-shadow 0.15s; | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .input-box:focus-within { | |
| border-color: var(--brand-light); | |
| box-shadow: 0 0 0 3px rgba(224,64,21,0.08), var(--shadow-sm); | |
| } | |
| .input-textarea { | |
| width: 100%; | |
| background: transparent; | |
| border: none; | |
| outline: none; | |
| font-family: inherit; | |
| font-size: 14.5px; | |
| color: var(--text-primary); | |
| line-height: 1.55; | |
| padding: 13px 16px 4px; | |
| resize: none; | |
| min-height: 50px; | |
| max-height: 220px; | |
| } | |
| .input-textarea::placeholder { color: var(--text-muted); } | |
| .input-toolbar { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 6px 10px 8px; | |
| } | |
| .input-left-actions { display: flex; gap: 4px; align-items: center; } | |
| .tool-btn { | |
| width: 30px; height: 30px; | |
| border: none; | |
| border-radius: 7px; | |
| background: transparent; | |
| color: var(--text-muted); | |
| cursor: pointer; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 13px; | |
| transition: background 0.12s, color 0.12s; | |
| } | |
| .tool-btn:hover { background: var(--bg-hover); color: var(--text-secondary); } | |
| .send-btn { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 7px 15px; | |
| background: var(--brand-mid); | |
| color: #fff; | |
| border: none; | |
| border-radius: 9px; | |
| font-family: inherit; | |
| font-size: 13.5px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: background 0.14s, transform 0.08s; | |
| } | |
| .send-btn:hover { background: var(--brand-deep); } | |
| .send-btn:active { transform: scale(0.97); } | |
| .send-btn.stop { background: #DC2626; } | |
| .send-btn.stop:hover { background: #B91C1C; } | |
| .input-hint { | |
| text-align: center; | |
| font-size: 11.5px; | |
| color: var(--text-muted); | |
| margin-top: 9px; | |
| } | |
| /* βββ Error state βββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| .error-msg { | |
| display: flex; | |
| align-items: center; | |
| gap: 7px; | |
| font-size: 13.5px; | |
| color: #C0310A; | |
| background: #FEF2EE; | |
| border: 1px solid #FCCDB8; | |
| border-radius: 8px; | |
| padding: 9px 13px; | |
| } | |
| /* βββ Responsive βββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| @media (max-width: 640px) { | |
| .sidebar { position: absolute; z-index: 20; height: 100%; box-shadow: var(--shadow-lg); } | |
| .sidebar.collapsed { width: 0; } | |
| .welcome-cards { grid-template-columns: 1fr; } | |
| } | |
| /* Scrollbar for prism code blocks */ | |
| .response-body pre::-webkit-scrollbar { height: 4px; } | |
| .response-body pre::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <!-- βββ SIDEBAR βββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <aside class="sidebar" id="sidebar"> | |
| <div class="sidebar-header"> | |
| <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/64d1faaa1ed6649d70d1fa2f/lZVm6Yuiif9cdr5KsnfZr.png" | |
| alt="VibeThinker" class="brand-logo"> | |
| <div> | |
| <div class="brand-name">VibeThinker</div> | |
| <span class="brand-tag">3B Β· WeiboAI</span> | |
| </div> | |
| </div> | |
| <div class="sidebar-body"> | |
| <!-- Parameters --> | |
| <div class="sidebar-section-label">Parameters</div> | |
| <div class="param-group"> | |
| <div class="param-row"> | |
| <span class="param-label">Temperature</span> | |
| <span class="param-val" id="val-temp">1.0</span> | |
| </div> | |
| <input type="range" id="param-temp" min="0" max="1.5" step="0.05" value="1.0"> | |
| </div> | |
| <div class="param-group"> | |
| <div class="param-row"> | |
| <span class="param-label">Top-P</span> | |
| <span class="param-val" id="val-topp">0.95</span> | |
| </div> | |
| <input type="range" id="param-topp" min="0" max="1" step="0.01" value="0.95"> | |
| </div> | |
| <div class="param-group"> | |
| <div class="param-row"> | |
| <span class="param-label">Max Tokens</span> | |
| <span class="param-val" id="val-tokens">4096</span> | |
| </div> | |
| <input type="range" id="param-tokens" min="256" max="32768" step="256" value="4096"> | |
| </div> | |
| <div class="param-group"> | |
| <div class="param-label" style="margin-bottom:6px">System Prompt</div> | |
| <textarea class="system-prompt-textarea" id="param-system">You are VibeThinker, a helpful and harmless AI assistant specialized in reasoning. You solve complex problems step-by-step to verify correctness.</textarea> | |
| </div> | |
| <!-- Presets --> | |
| <div class="sidebar-section-label" style="margin-top:4px">Try a prompt</div> | |
| <button class="preset-btn" onclick="loadPreset('card')"> | |
| <span class="preset-icon"><i class="fa-solid fa-dice"></i></span> | |
| Probability β card deck | |
| </button> | |
| <button class="preset-btn" onclick="loadPreset('palindrome')"> | |
| <span class="preset-icon"><i class="fa-solid fa-code"></i></span> | |
| Algorithm β longest palindrome | |
| </button> | |
| <button class="preset-btn" onclick="loadPreset('logic')"> | |
| <span class="preset-icon"><i class="fa-solid fa-box"></i></span> | |
| Logic β labeled fruit boxes | |
| </button> | |
| </div><!-- /sidebar-body --> | |
| <div class="sidebar-footer"> | |
| <a class="footer-link" href="https://huggingface.co/KyleHessling1/Qwopus3.6-27B-Fusion-GGUF" target="_blank"> | |
| <i class="fa-solid fa-cube"></i> Model Card | |
| </a> | |
| <a class="footer-link" href="https://arxiv.org/abs/2606.16140" target="_blank"> | |
| <i class="fa-regular fa-file-lines"></i> Research Paper | |
| </a> | |
| <span class="footer-link" style="cursor:default"> | |
| <i class="fa-solid fa-scale-balanced"></i> MIT License Β· WeiboAI 2026 | |
| </span> | |
| </div> | |
| </aside><!-- /sidebar --> | |
| <!-- βββ MAIN ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <div class="main"> | |
| <!-- Top bar --> | |
| <div class="topbar"> | |
| <div class="topbar-left"> | |
| <button class="toggle-sidebar-btn" id="toggle-sidebar-btn" onclick="toggleSidebar()" title="Toggle sidebar"> | |
| <i class="fa-solid fa-sidebar"></i> | |
| </button> | |
| <div class="model-pill"> | |
| <div class="model-dot" id="status-dot"></div> | |
| <span id="status-text">VibeThinker-3B</span> | |
| </div> | |
| </div> | |
| <div class="topbar-right"> | |
| <button class="topbar-action-btn" title="Clear chat" onclick="clearChat()"> | |
| <i class="fa-regular fa-trash-can"></i> | |
| </button> | |
| <a class="topbar-action-btn" href="https://huggingface.co/WeiboAI/VibeThinker-3B" target="_blank" title="Model on HuggingFace"> | |
| π€ | |
| </a> | |
| </div> | |
| </div> | |
| <!-- Chat scroll --> | |
| <div class="chat-scroll" id="chat-scroll"> | |
| <div class="chat-inner" id="chat-inner"> | |
| <!-- Welcome --> | |
| <div class="welcome" id="welcome-screen"> | |
| <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/64d1faaa1ed6649d70d1fa2f/lZVm6Yuiif9cdr5KsnfZr.png" | |
| alt="VibeThinker" class="welcome-logo"> | |
| <h1 class="welcome-title">Qwopus-27b</h1> | |
| <p class="welcome-sub"> | |
| Qwopus works!</p> | |
| <div class="welcome-chips"> | |
| <div class="chip" onclick="loadPreset('palindrome')"><i class="fa-solid fa-code"></i> Coding</div> | |
| <div class="chip" onclick="loadPreset('card')"><i class="fa-solid fa-calculator"></i> Math</div> | |
| <div class="chip" onclick="loadPreset('logic')"><i class="fa-solid fa-puzzle-piece"></i> Logic</div> | |
| </div> | |
| <div class="welcome-cards"> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-brain"></i></div> | |
| <div class="wc-title">Chain-of-Thought</div> | |
| <div class="wc-desc">Reasoning steps rendered live inside <code><think></code> blocks before the final answer.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-trophy"></i></div> | |
| <div class="wc-title">Frontier Accuracy</div> | |
| <div class="wc-desc">76.4% on IMO-AnswerBench β matching models 200Γ larger.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-bolt"></i></div> | |
| <div class="wc-title">Token Streaming</div> | |
| <div class="wc-desc">Gradio Server + ZeroGPU stream every token in real time.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-brands fa-python"></i></div> | |
| <div class="wc-title">96.1% LeetCode</div> | |
| <div class="wc-desc">123/128 first-attempt submissions on recent weekly contests.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div><!-- /chat-inner --> | |
| </div><!-- /chat-scroll --> | |
| <!-- Input --> | |
| <div class="input-area"> | |
| <div class="input-inner"> | |
| <div class="input-box"> | |
| <textarea class="input-textarea" id="chat-input" | |
| placeholder="Ask a math, logic, or coding questionβ¦" | |
| rows="1" | |
| oninput="autoResize(this)"></textarea> | |
| <div class="input-toolbar"> | |
| <div class="input-left-actions"> | |
| <button class="tool-btn" title="Clear chat" onclick="clearChat()"> | |
| <i class="fa-regular fa-trash-can"></i> | |
| </button> | |
| <button class="tool-btn" title="Parameters" onclick="toggleSidebar()"> | |
| <i class="fa-solid fa-sliders"></i> | |
| </button> | |
| </div> | |
| <button class="send-btn" id="send-btn" onclick="handleSubmit()"> | |
| <i class="fa-solid fa-paper-plane" id="send-icon"></i> | |
| <span id="send-text">Send</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="input-hint">Qwopus can make mistakes. Verify important results.</div> | |
| </div> | |
| </div> | |
| </div><!-- /main --> | |
| </div><!-- /app --> | |
| <!-- βββ SCRIPT ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ --> | |
| <script type="module"> | |
| import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; | |
| let client = null; | |
| let activeJob = null; | |
| let isGenerating = false; | |
| let currentMsgId = null; | |
| let timerInterval = null; | |
| let sidebarOpen = true; | |
| // ββ Init ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.addEventListener("DOMContentLoaded", () => { | |
| setupSliders(); | |
| initClient(); | |
| }); | |
| async function initClient() { | |
| try { | |
| setStatus("connecting", "Connectingβ¦"); | |
| client = await Client.connect(window.location.origin); | |
| setStatus("ready", "VibeThinker-3B"); | |
| } catch (e) { | |
| console.error("Client connect failed:", e); | |
| setStatus("error", "Connection error"); | |
| } | |
| } | |
| // ββ Sliders βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function setupSliders() { | |
| [["param-temp","val-temp"],["param-topp","val-topp"],["param-tokens","val-tokens"]] | |
| .forEach(([inputId, valId]) => { | |
| const el = document.getElementById(inputId); | |
| const vl = document.getElementById(valId); | |
| el.addEventListener("input", () => { vl.textContent = el.value; }); | |
| }); | |
| } | |
| // ββ Sidebar toggle ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.toggleSidebar = function() { | |
| const sidebar = document.getElementById("sidebar"); | |
| sidebarOpen = !sidebarOpen; | |
| sidebar.classList.toggle("collapsed", !sidebarOpen); | |
| }; | |
| // ββ Presets βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.loadPreset = function(type) { | |
| const ta = document.getElementById("chat-input"); | |
| const map = { | |
| palindrome: "Write a Python function to solve the Longest Palindromic Substring problem, with full complexity analysis.", | |
| card: "If a card is drawn from a standard deck, what is the probability it is a spade or a face card?", | |
| logic: "Three boxes are labeled 'Apples', 'Oranges', and 'Mixed'. All labels are wrong. Draw one fruit from one box β how do you correctly label all three boxes?" | |
| }; | |
| ta.value = map[type] || ""; | |
| autoResize(ta); | |
| ta.focus(); | |
| if (window.innerWidth <= 640) document.getElementById("sidebar").classList.add("collapsed"); | |
| }; | |
| // ββ Auto-resize textarea ββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.autoResize = function(el) { | |
| el.style.height = "auto"; | |
| el.style.height = Math.min(el.scrollHeight, 220) + "px"; | |
| }; | |
| // ββ Status indicator ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function setStatus(state, label) { | |
| const dot = document.getElementById("status-dot"); | |
| const txt = document.getElementById("status-text"); | |
| txt.textContent = label; | |
| dot.className = "model-dot"; | |
| if (state === "connecting" || state === "generating") dot.classList.add("busy"); | |
| if (state === "error") dot.style.background = "#DC2626"; | |
| else dot.style.background = ""; | |
| } | |
| // ββ Submit ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.handleSubmit = async function() { | |
| if (isGenerating) { | |
| if (activeJob) { try { activeJob.cancel(); } catch(_) {} } | |
| isGenerating = false; | |
| clearInterval(timerInterval); | |
| resetBtn(); | |
| setStatus("ready", "VibeThinker-3B"); | |
| return; | |
| } | |
| const ta = document.getElementById("chat-input"); | |
| const prompt = ta.value.trim(); | |
| if (!prompt) return; | |
| if (!client) { alert("Server not connected. Please waitβ¦"); initClient(); return; } | |
| // Hide welcome | |
| const ws = document.getElementById("welcome-screen"); | |
| if (ws) ws.remove(); | |
| ta.value = ""; | |
| autoResize(ta); | |
| appendUserMsg(prompt); | |
| currentMsgId = appendAssistantMsg(); | |
| setToStop(); | |
| isGenerating = true; | |
| setStatus("generating", "Thinkingβ¦"); | |
| const temp = parseFloat(document.getElementById("param-temp").value); | |
| const topp = parseFloat(document.getElementById("param-topp").value); | |
| const tokens = parseInt(document.getElementById("param-tokens").value); | |
| const system = document.getElementById("param-system").value; | |
| // Start elapsed timer | |
| let elapsed = 0; | |
| const timerEl = document.getElementById("think-timer-" + currentMsgId); | |
| if (timerEl) { | |
| timerInterval = setInterval(() => { | |
| elapsed += 0.1; | |
| timerEl.textContent = `${elapsed.toFixed(1)}s`; | |
| }, 100); | |
| } | |
| try { | |
| activeJob = client.submit("/predict", { | |
| message: prompt, | |
| system_prompt: system, | |
| temperature: temp, | |
| top_p: topp, | |
| max_tokens: tokens | |
| }); | |
| (async () => { | |
| try { | |
| for await (const msg of activeJob) { | |
| if (msg && msg.data) { | |
| const text = msg.data[0]; | |
| if (typeof text === "string") updateStream(currentMsgId, text); | |
| } | |
| } | |
| finalizeStream(currentMsgId); | |
| } catch (err) { | |
| console.error("Stream error:", err); | |
| clearInterval(timerInterval); | |
| showError(currentMsgId, "An error occurred during generation. Please try again."); | |
| isGenerating = false; | |
| resetBtn(); | |
| setStatus("ready", "VibeThinker-3B"); | |
| } | |
| })(); | |
| } catch (err) { | |
| console.error("Submit failed:", err); | |
| clearInterval(timerInterval); | |
| showError(currentMsgId, "Failed to submit request."); | |
| isGenerating = false; | |
| resetBtn(); | |
| setStatus("ready", "VibeThinker-3B"); | |
| } | |
| }; | |
| // ββ Button states βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function setToStop() { | |
| document.getElementById("send-btn").className = "send-btn stop"; | |
| document.getElementById("send-icon").className = "fa-solid fa-stop"; | |
| document.getElementById("send-text").textContent = "Stop"; | |
| } | |
| function resetBtn() { | |
| document.getElementById("send-btn").className = "send-btn"; | |
| document.getElementById("send-icon").className = "fa-solid fa-paper-plane"; | |
| document.getElementById("send-text").textContent = "Send"; | |
| } | |
| // ββ Append messages βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function appendUserMsg(text) { | |
| const inner = document.getElementById("chat-inner"); | |
| const g = document.createElement("div"); | |
| g.className = "message-group"; | |
| g.innerHTML = ` | |
| <div class="user-row"> | |
| <div class="user-bubble">${escHtml(text)}</div> | |
| </div>`; | |
| inner.appendChild(g); | |
| scrollBottom(); | |
| } | |
| function appendAssistantMsg() { | |
| const inner = document.getElementById("chat-inner"); | |
| const id = "msg-" + Date.now(); | |
| const g = document.createElement("div"); | |
| g.className = "message-group"; | |
| g.id = id; | |
| g.innerHTML = ` | |
| <div class="assistant-row"> | |
| <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/64d1faaa1ed6649d70d1fa2f/lZVm6Yuiif9cdr5KsnfZr.png" | |
| alt="VibeThinker" class="assistant-avatar"> | |
| <div class="assistant-content"> | |
| <div class="assistant-name">VibeThinker-3B</div> | |
| <!-- think box (hidden until we see <think>) --> | |
| <div class="think-box" id="think-box-${id}" style="display:none"> | |
| <div class="think-header" onclick="toggleThink('${id}')"> | |
| <div class="think-header-left"> | |
| <i class="fa-solid fa-spinner think-spinner" id="think-spin-${id}"></i> | |
| <span id="think-label-${id}">Thinkingβ¦</span> | |
| </div> | |
| <span class="think-timer" id="think-timer-${id}">0.0s</span> | |
| </div> | |
| <div class="think-body" id="think-body-${id}" style="display:none"></div> | |
| </div> | |
| <!-- response body --> | |
| <div class="response-body" id="resp-body-${id}"> | |
| <div class="typing"> | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| <div class="typing-dot"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div>`; | |
| inner.appendChild(g); | |
| scrollBottom(); | |
| return id; | |
| } | |
| // ββ Stream update βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function updateStream(id, fullText) { | |
| const { thinking, response, thinkDone } = parseStream(fullText); | |
| const thinkBox = document.getElementById("think-box-" + id); | |
| const thinkBody = document.getElementById("think-body-" + id); | |
| const thinkSpin = document.getElementById("think-spin-" + id); | |
| const thinkLbl = document.getElementById("think-label-" + id); | |
| const timerEl = document.getElementById("think-timer-" + id); | |
| const respBody = document.getElementById("resp-body-" + id); | |
| if (thinking) { | |
| thinkBox.style.display = "block"; | |
| thinkBody.textContent = thinking; | |
| } | |
| if (thinkDone) { | |
| clearInterval(timerInterval); | |
| thinkSpin.className = "fa-solid fa-check think-check"; | |
| thinkLbl.textContent = "Reasoning complete"; | |
| // Auto-collapse body once done | |
| if (!thinkBody.dataset.collapsed) { | |
| thinkBody.style.display = "none"; | |
| thinkBody.dataset.collapsed = "true"; | |
| } | |
| } | |
| if (response) { | |
| respBody.innerHTML = marked.parse(response); | |
| setupCodeHeaders(respBody); | |
| Prism.highlightAllUnder(respBody); | |
| } else if (!thinkDone) { | |
| // Still thinking β keep typing dots if no response yet | |
| } | |
| scrollBottom(); | |
| debounceMath(); | |
| } | |
| function finalizeStream(id) { | |
| clearInterval(timerInterval); | |
| isGenerating = false; | |
| resetBtn(); | |
| setStatus("ready", "VibeThinker-3B"); | |
| if (window.MathJax?.typesetPromise) window.MathJax.typesetPromise(); | |
| } | |
| function showError(id, msg) { | |
| const respBody = document.getElementById("resp-body-" + id); | |
| if (respBody) { | |
| respBody.innerHTML = `<div class="error-msg"><i class="fa-solid fa-triangle-exclamation"></i>${escHtml(msg)}</div>`; | |
| } | |
| } | |
| // ββ Parse <think>β¦</think> ββββββββββββββββββββββββββββββββββββββββββββ | |
| function parseStream(text) { | |
| if (!text || typeof text !== "string") return { thinking: "", response: "", thinkDone: false }; | |
| if (!text.includes("<think>")) return { thinking: "", response: text, thinkDone: false }; | |
| const start = text.indexOf("<think>") + 7; | |
| if (text.includes("</think>")) { | |
| const end = text.indexOf("</think>"); | |
| return { | |
| thinking: text.substring(start, end).trim(), | |
| response: text.substring(end + 8).trim(), | |
| thinkDone: true | |
| }; | |
| } | |
| return { thinking: text.substring(start), response: "", thinkDone: false }; | |
| } | |
| // ββ Think accordion toggle βββββββββββββββββββββββββββββββββββββββββββββ | |
| window.toggleThink = function(id) { | |
| const body = document.getElementById("think-body-" + id); | |
| body.style.display = body.style.display === "none" ? "block" : "none"; | |
| }; | |
| // ββ Code block copy buttons βββββββββββββββββββββββββββββββββββββββββββ | |
| function setupCodeHeaders(container) { | |
| container.querySelectorAll("pre").forEach(pre => { | |
| if (pre.querySelector(".code-header")) return; | |
| const code = pre.querySelector("code"); | |
| let lang = ""; | |
| (code?.className || "").split(" ").forEach(c => { | |
| if (c.startsWith("language-")) lang = c.replace("language-", ""); | |
| }); | |
| const header = document.createElement("div"); | |
| header.className = "code-header"; | |
| header.innerHTML = ` | |
| <span>${lang.toUpperCase() || "CODE"}</span> | |
| <button class="code-copy-btn" onclick="copyCode(this)"> | |
| <i class="fa-regular fa-copy"></i> Copy | |
| </button>`; | |
| pre.insertBefore(header, code); | |
| }); | |
| } | |
| window.copyCode = function(btn) { | |
| const code = btn.closest("pre").querySelector("code")?.textContent || ""; | |
| navigator.clipboard.writeText(code).then(() => { | |
| btn.innerHTML = '<i class="fa-solid fa-check" style="color:#22A757"></i> Copied'; | |
| setTimeout(() => { btn.innerHTML = '<i class="fa-regular fa-copy"></i> Copy'; }, 2000); | |
| }); | |
| }; | |
| // ββ Math debounce βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let mathTimer = null; | |
| function debounceMath() { | |
| clearTimeout(mathTimer); | |
| mathTimer = setTimeout(() => { | |
| if (window.MathJax?.typesetPromise) window.MathJax.typesetPromise(); | |
| }, 600); | |
| } | |
| // ββ Clear chat ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| window.clearChat = function() { | |
| if (isGenerating) { | |
| try { activeJob?.cancel(); } catch(_) {} | |
| isGenerating = false; | |
| clearInterval(timerInterval); | |
| resetBtn(); | |
| setStatus("ready", "VibeThinker-3B"); | |
| } | |
| const inner = document.getElementById("chat-inner"); | |
| inner.innerHTML = ` | |
| <div class="welcome" id="welcome-screen"> | |
| <img src="https://cdn-avatars.huggingface.co/v1/production/uploads/64d1faaa1ed6649d70d1fa2f/lZVm6Yuiif9cdr5KsnfZr.png" | |
| alt="VibeThinker" class="welcome-logo"> | |
| <h1 class="welcome-title">VibeThinker-3B</h1> | |
| <p class="welcome-sub"> | |
| A 3B-parameter reasoning model by WeiboAI, achieving frontier-level performance on mathematics, coding, and STEM β with transparent chain-of-thought. | |
| </p> | |
| <div class="welcome-chips"> | |
| <div class="chip" onclick="loadPreset('palindrome')"><i class="fa-solid fa-code"></i> Coding</div> | |
| <div class="chip" onclick="loadPreset('card')"><i class="fa-solid fa-calculator"></i> Math</div> | |
| <div class="chip" onclick="loadPreset('logic')"><i class="fa-solid fa-puzzle-piece"></i> Logic</div> | |
| </div> | |
| <div class="welcome-cards"> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-brain"></i></div> | |
| <div class="wc-title">Chain-of-Thought</div> | |
| <div class="wc-desc">Reasoning rendered live in <code><think></code> blocks.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-trophy"></i></div> | |
| <div class="wc-title">Frontier Accuracy</div> | |
| <div class="wc-desc">76.4% on IMO-AnswerBench β matching models 200Γ larger.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-solid fa-bolt"></i></div> | |
| <div class="wc-title">Token Streaming</div> | |
| <div class="wc-desc">Gradio Server + ZeroGPU stream every token live.</div> | |
| </div> | |
| <div class="welcome-card"> | |
| <div class="wc-icon"><i class="fa-brands fa-python"></i></div> | |
| <div class="wc-title">96.1% LeetCode</div> | |
| <div class="wc-desc">123/128 first-attempt contest submissions.</div> | |
| </div> | |
| </div> | |
| </div>`; | |
| }; | |
| // ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function scrollBottom() { | |
| const sc = document.getElementById("chat-scroll"); | |
| sc.scrollTop = sc.scrollHeight; | |
| } | |
| function escHtml(s) { | |
| return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") | |
| .replace(/"/g,""").replace(/'/g,"'"); | |
| } | |
| // Enter to submit, Shift+Enter for newline | |
| document.getElementById("chat-input").addEventListener("keydown", e => { | |
| if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSubmit(); } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |