Spaces:
Running on Zero
Running on Zero
Show reasoning in collapsible block; simplify header nav
Browse files- app.py +1 -7
- index.html +39 -8
app.py
CHANGED
|
@@ -71,13 +71,7 @@ def chat(message: str,
|
|
| 71 |
reply = ""
|
| 72 |
for token in streamer:
|
| 73 |
reply += token
|
| 74 |
-
#
|
| 75 |
-
# "assistant to=user" marker before the final response.
|
| 76 |
-
if "to=user" in reply:
|
| 77 |
-
final = reply.rsplit("to=user", 1)[1].strip()
|
| 78 |
-
else:
|
| 79 |
-
final = ""
|
| 80 |
-
yield final if final else "💭 thinking…"
|
| 81 |
thread.join()
|
| 82 |
|
| 83 |
|
|
|
|
| 71 |
reply = ""
|
| 72 |
for token in streamer:
|
| 73 |
reply += token
|
| 74 |
+
yield reply # raw stream; frontend splits reasoning from final reply
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
thread.join()
|
| 76 |
|
| 77 |
|
index.html
CHANGED
|
@@ -63,6 +63,9 @@
|
|
| 63 |
.bot { align-self: flex-start; background: var(--card); border: 1px solid var(--border); color: #eef2fb; border-bottom-left-radius: 6px; }
|
| 64 |
.msg img { max-width: 240px; border-radius: 12px; display: block; margin-bottom: 8px; }
|
| 65 |
.sys { align-self: center; color: var(--muted); font-size: 12px; background: none; }
|
|
|
|
|
|
|
|
|
|
| 66 |
.bot.typing span::after { content: "▊"; animation: blink 1s steps(1) infinite; color: #8ab4ff; }
|
| 67 |
@keyframes blink { 50% { opacity: 0; } }
|
| 68 |
|
|
@@ -121,10 +124,7 @@
|
|
| 121 |
</div>
|
| 122 |
<nav>
|
| 123 |
<a href="https://huggingface.co/meta-models/Muse-Glimmer-30B" target="_blank">Model Card</a>
|
| 124 |
-
<a href="https://arxiv.org/abs/2602.06036" target="_blank">DFlash Paper</a>
|
| 125 |
-
<a href="https://arxiv.org/abs/2504.13181" target="_blank">Perception Encoder</a>
|
| 126 |
</nav>
|
| 127 |
-
<button class="cta" onclick="document.getElementById('input').focus()">Try Muse Glimmer</button>
|
| 128 |
</header>
|
| 129 |
|
| 130 |
<div class="orb">
|
|
@@ -216,6 +216,37 @@ function addMsg(role, text, imgUrl) {
|
|
| 216 |
return t;
|
| 217 |
}
|
| 218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
function setBusy(b) {
|
| 220 |
sendBtn.style.display = b ? "none" : "";
|
| 221 |
stopBtn.style.display = b ? "" : "none";
|
|
@@ -233,8 +264,8 @@ async function send() {
|
|
| 233 |
input.style.height = "auto";
|
| 234 |
setBusy(true);
|
| 235 |
|
| 236 |
-
const
|
| 237 |
-
|
| 238 |
try {
|
| 239 |
currentJob = client.submit("/chat", {
|
| 240 |
message: text,
|
|
@@ -251,16 +282,16 @@ async function send() {
|
|
| 251 |
}
|
| 252 |
if (event.type === "data") {
|
| 253 |
finalText = event.data[0];
|
| 254 |
-
|
| 255 |
chatEl.scrollTop = chatEl.scrollHeight;
|
| 256 |
}
|
| 257 |
}
|
| 258 |
history.push({ role: "user", content: text || "[image]" });
|
| 259 |
history.push({ role: "assistant", content: finalText });
|
| 260 |
} catch (e) {
|
| 261 |
-
|
| 262 |
} finally {
|
| 263 |
-
|
| 264 |
setBusy(false);
|
| 265 |
clearImage();
|
| 266 |
queueEl.textContent = "—";
|
|
|
|
| 63 |
.bot { align-self: flex-start; background: var(--card); border: 1px solid var(--border); color: #eef2fb; border-bottom-left-radius: 6px; }
|
| 64 |
.msg img { max-width: 240px; border-radius: 12px; display: block; margin-bottom: 8px; }
|
| 65 |
.sys { align-self: center; color: var(--muted); font-size: 12px; background: none; }
|
| 66 |
+
.reasoning { margin-bottom: 8px; border-left: 2px solid var(--border); padding-left: 10px; }
|
| 67 |
+
.reasoning summary { cursor: pointer; color: #8ab4ff; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
|
| 68 |
+
.reasoning-body { color: var(--muted); font-size: 13px; font-style: italic; margin-top: 6px; white-space: pre-wrap; }
|
| 69 |
.bot.typing span::after { content: "▊"; animation: blink 1s steps(1) infinite; color: #8ab4ff; }
|
| 70 |
@keyframes blink { 50% { opacity: 0; } }
|
| 71 |
|
|
|
|
| 124 |
</div>
|
| 125 |
<nav>
|
| 126 |
<a href="https://huggingface.co/meta-models/Muse-Glimmer-30B" target="_blank">Model Card</a>
|
|
|
|
|
|
|
| 127 |
</nav>
|
|
|
|
| 128 |
</header>
|
| 129 |
|
| 130 |
<div class="orb">
|
|
|
|
| 216 |
return t;
|
| 217 |
}
|
| 218 |
|
| 219 |
+
// Render a bot message, splitting the model's reasoning preamble
|
| 220 |
+
// (everything before the "to=user" marker) into a collapsible block.
|
| 221 |
+
function renderBot(div, raw) {
|
| 222 |
+
div.innerHTML = "";
|
| 223 |
+
let reasoning = "", final = raw;
|
| 224 |
+
if (raw.includes("to=user")) {
|
| 225 |
+
const idx = raw.lastIndexOf("to=user");
|
| 226 |
+
reasoning = raw.slice(0, idx).replace(/\.?assistant\s*$/, "").trim();
|
| 227 |
+
final = raw.slice(idx + "to=user".length).trim();
|
| 228 |
+
} else {
|
| 229 |
+
reasoning = raw.trim();
|
| 230 |
+
final = "";
|
| 231 |
+
}
|
| 232 |
+
if (reasoning) {
|
| 233 |
+
const det = document.createElement("details");
|
| 234 |
+
det.className = "reasoning";
|
| 235 |
+
det.open = !final; // expand while still thinking, collapse once answer starts
|
| 236 |
+
const sum = document.createElement("summary");
|
| 237 |
+
sum.textContent = final ? "Reasoning" : "Thinking…";
|
| 238 |
+
det.appendChild(sum);
|
| 239 |
+
const body = document.createElement("div");
|
| 240 |
+
body.className = "reasoning-body";
|
| 241 |
+
body.textContent = reasoning;
|
| 242 |
+
det.appendChild(body);
|
| 243 |
+
div.appendChild(det);
|
| 244 |
+
}
|
| 245 |
+
const t = document.createElement("span");
|
| 246 |
+
t.textContent = final || "💭 thinking…";
|
| 247 |
+
div.appendChild(t);
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
function setBusy(b) {
|
| 251 |
sendBtn.style.display = b ? "none" : "";
|
| 252 |
stopBtn.style.display = b ? "" : "none";
|
|
|
|
| 264 |
input.style.height = "auto";
|
| 265 |
setBusy(true);
|
| 266 |
|
| 267 |
+
const botDiv = addMsg("bot", "").parentElement;
|
| 268 |
+
botDiv.classList.add("typing");
|
| 269 |
try {
|
| 270 |
currentJob = client.submit("/chat", {
|
| 271 |
message: text,
|
|
|
|
| 282 |
}
|
| 283 |
if (event.type === "data") {
|
| 284 |
finalText = event.data[0];
|
| 285 |
+
renderBot(botDiv, finalText);
|
| 286 |
chatEl.scrollTop = chatEl.scrollHeight;
|
| 287 |
}
|
| 288 |
}
|
| 289 |
history.push({ role: "user", content: text || "[image]" });
|
| 290 |
history.push({ role: "assistant", content: finalText });
|
| 291 |
} catch (e) {
|
| 292 |
+
botDiv.textContent = "⚠️ " + (e.message || e);
|
| 293 |
} finally {
|
| 294 |
+
botDiv.classList.remove("typing");
|
| 295 |
setBusy(false);
|
| 296 |
clearImage();
|
| 297 |
queueEl.textContent = "—";
|