Spaces:
Running on Zero
Running on Zero
UI: direct Gradio SSE adapter, bidi lists, no page overflow
Browse files- diba-ui.css +1 -1
- diba-ui.js +31 -10
diba-ui.css
CHANGED
|
@@ -10,7 +10,7 @@
|
|
| 10 |
--accent: #4CB58C; --accent-ink: #0B1511; --accent-soft: #1E3A2F; --danger: #F2B8B5; --shadow: 0 6px 24px rgba(0, 0, 0, .35);
|
| 11 |
}
|
| 12 |
|
| 13 |
-
html, body { height: 100%; }
|
| 14 |
body.diba-lock { overflow: hidden !important; }
|
| 15 |
#diba-root, #diba-root * { box-sizing: border-box; }
|
| 16 |
#diba-root {
|
|
|
|
| 10 |
--accent: #4CB58C; --accent-ink: #0B1511; --accent-soft: #1E3A2F; --danger: #F2B8B5; --shadow: 0 6px 24px rgba(0, 0, 0, .35);
|
| 11 |
}
|
| 12 |
|
| 13 |
+
html, body { height: 100%; margin: 0; }
|
| 14 |
body.diba-lock { overflow: hidden !important; }
|
| 15 |
#diba-root, #diba-root * { box-sizing: border-box; }
|
| 16 |
#diba-root {
|
diba-ui.js
CHANGED
|
@@ -155,16 +155,35 @@
|
|
| 155 |
}
|
| 156 |
}
|
| 157 |
|
| 158 |
-
|
|
|
|
| 159 |
async function* streamGradio(messages) {
|
| 160 |
-
|
| 161 |
-
const
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
}
|
| 169 |
}
|
| 170 |
|
|
@@ -284,7 +303,7 @@
|
|
| 284 |
async function runAssistant() {
|
| 285 |
const c = current(); if (!c) return;
|
| 286 |
const history = c.messages.filter((m) => !m.error && m.content).map((m) => ({ role: m.role, content: m.content }));
|
| 287 |
-
const bot = { role: "assistant", content: "", pending: true, cold: BACKEND === "gradio" && !
|
| 288 |
c.messages.push(bot); renderThread(); toBottom(true);
|
| 289 |
S.streaming = true; S.controller = new AbortController(); setSendState();
|
| 290 |
let frame = 0; let latest = "";
|
|
@@ -376,6 +395,8 @@
|
|
| 376 |
applyChrome(); toBottom(true); setSendState();
|
| 377 |
Promise.all([loadScript(CDN.marked), loadScript(CDN.purify), loadScript(CDN.hljs)]).then(() => { renderThread(); toBottom(true); }).catch(() => { /* plain text fallback */ });
|
| 378 |
if (window.innerWidth > 820) el.input.focus();
|
|
|
|
|
|
|
| 379 |
}
|
| 380 |
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", boot); else boot();
|
| 381 |
})();
|
|
|
|
| 155 |
}
|
| 156 |
}
|
| 157 |
|
| 158 |
+
// Gradio REST streaming protocol: POST /gradio_api/call/<api> -> {event_id}; GET .../<event_id> -> SSE (generating|complete|error)
|
| 159 |
+
let gradioWarm = false;
|
| 160 |
async function* streamGradio(messages) {
|
| 161 |
+
const base = window.location.origin + window.location.pathname.replace(/\/+$/, "");
|
| 162 |
+
const signal = S.controller.signal;
|
| 163 |
+
const start = await fetch(base + "/gradio_api/call/chat_stream", {
|
| 164 |
+
method: "POST", headers: { "Content-Type": "application/json" }, signal,
|
| 165 |
+
body: JSON.stringify({ data: [JSON.stringify(messages.slice(-16)), S.settings.temperature, S.settings.max_tokens] }),
|
| 166 |
+
});
|
| 167 |
+
if (!start.ok) throw new Error("HTTP " + start.status);
|
| 168 |
+
const { event_id } = await start.json();
|
| 169 |
+
const res = await fetch(base + "/gradio_api/call/chat_stream/" + event_id, { signal });
|
| 170 |
+
if (!res.ok || !res.body) throw new Error("HTTP " + res.status);
|
| 171 |
+
const reader = res.body.getReader(); const dec = new TextDecoder(); let buf = ""; let event = "";
|
| 172 |
+
for (;;) {
|
| 173 |
+
const { value, done } = await reader.read(); if (done) return;
|
| 174 |
+
buf += dec.decode(value, { stream: true });
|
| 175 |
+
let i;
|
| 176 |
+
while ((i = buf.indexOf("\n")) >= 0) {
|
| 177 |
+
const line = buf.slice(0, i).replace(/\r$/, ""); buf = buf.slice(i + 1);
|
| 178 |
+
if (line.startsWith("event:")) { event = line.slice(6).trim(); continue; }
|
| 179 |
+
if (!line.startsWith("data:")) continue;
|
| 180 |
+
const raw = line.slice(5).trim();
|
| 181 |
+
if (event === "error") throw new Error(raw || "gradio error");
|
| 182 |
+
if (event === "generating" || event === "complete") {
|
| 183 |
+
try { const arr = JSON.parse(raw); if (Array.isArray(arr) && typeof arr[0] === "string") { gradioWarm = true; yield arr[0]; } } catch (e) { /* heartbeat */ }
|
| 184 |
+
if (event === "complete") return;
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
}
|
| 188 |
}
|
| 189 |
|
|
|
|
| 303 |
async function runAssistant() {
|
| 304 |
const c = current(); if (!c) return;
|
| 305 |
const history = c.messages.filter((m) => !m.error && m.content).map((m) => ({ role: m.role, content: m.content }));
|
| 306 |
+
const bot = { role: "assistant", content: "", pending: true, cold: BACKEND === "gradio" && !gradioWarm };
|
| 307 |
c.messages.push(bot); renderThread(); toBottom(true);
|
| 308 |
S.streaming = true; S.controller = new AbortController(); setSendState();
|
| 309 |
let frame = 0; let latest = "";
|
|
|
|
| 395 |
applyChrome(); toBottom(true); setSendState();
|
| 396 |
Promise.all([loadScript(CDN.marked), loadScript(CDN.purify), loadScript(CDN.hljs)]).then(() => { renderThread(); toBottom(true); }).catch(() => { /* plain text fallback */ });
|
| 397 |
if (window.innerWidth > 820) el.input.focus();
|
| 398 |
+
const autoQ = qp.get("q"); // test hook: ?q=... sends one message on load
|
| 399 |
+
if (autoQ && location.hash !== "#demo") setTimeout(() => { newChat(); sendMessage(autoQ); }, 1200);
|
| 400 |
}
|
| 401 |
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", boot); else boot();
|
| 402 |
})();
|