mirror of
https://github.com/multipleof4/devsune.git
synced 2026-01-14 08:27:55 +00:00
This build was committed by a bot.
This commit is contained in:
178
docs/sw.js
178
docs/sw.js
@@ -1,114 +1,94 @@
|
|||||||
self.addEventListener("install", (e) => e.waitUntil(self.skipWaiting()));
|
const CH = "chat-stream-v1";
|
||||||
|
let bc, streams = /* @__PURE__ */ new Map();
|
||||||
|
self.addEventListener("install", (e) => self.skipWaiting());
|
||||||
self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
|
self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
|
||||||
const ch = new BroadcastChannel("llm-stream");
|
function send(m) {
|
||||||
const streams = /* @__PURE__ */ new Map();
|
try {
|
||||||
const send = (m) => ch.postMessage(m);
|
bc || (bc = new BroadcastChannel(CH));
|
||||||
const parseSSE = async (res, emit, signal) => {
|
bc.postMessage(m);
|
||||||
const r = res.body.getReader(), d = new TextDecoder("utf-8");
|
} catch {
|
||||||
let buf = "";
|
}
|
||||||
const doneOnce = () => emit("", true);
|
}
|
||||||
for (; ; ) {
|
function hint(x) {
|
||||||
const { value, done } = await r.read();
|
x = String(x || "");
|
||||||
if (done) break;
|
if (/401|unauthorized/i.test(x)) return "Unauthorized (check API key).";
|
||||||
buf += d.decode(value, { stream: true });
|
if (/429|rate/i.test(x)) return "Rate limited (slow down or upgrade).";
|
||||||
let i;
|
if (/403|forbidden|access/i.test(x)) return "Forbidden (model or key scope).";
|
||||||
while ((i = buf.indexOf("\n\n")) !== -1) {
|
return "Request failed.";
|
||||||
const chunk = buf.slice(0, i).trim();
|
}
|
||||||
buf = buf.slice(i + 2);
|
async function start(id, p) {
|
||||||
if (!chunk) continue;
|
bc || (bc = new BroadcastChannel(CH));
|
||||||
if (chunk.startsWith("data:")) {
|
const body = typeof p.body === "string" ? p.body : JSON.stringify(p.body || {}), ctrl = new AbortController();
|
||||||
const data = chunk.slice(5).trim();
|
let done = false, buf = "";
|
||||||
|
streams.set(id, { ctrl, buf: () => buf, done: () => done });
|
||||||
|
try {
|
||||||
|
const r = await fetch(p.url, { method: "POST", headers: p.headers || {}, body, signal: ctrl.signal });
|
||||||
|
if (!r.ok) throw new Error(await r.text().catch(() => "") || "HTTP " + r.status);
|
||||||
|
const rd = r.body.getReader(), dc = new TextDecoder("utf-8");
|
||||||
|
let acc = "";
|
||||||
|
const doneOnce = () => {
|
||||||
|
if (done) return;
|
||||||
|
done = true;
|
||||||
|
send({ t: "done", id });
|
||||||
|
};
|
||||||
|
for (; ; ) {
|
||||||
|
const { value, done: d } = await rd.read();
|
||||||
|
if (d) break;
|
||||||
|
acc += dc.decode(value, { stream: true });
|
||||||
|
let i;
|
||||||
|
while ((i = acc.indexOf("\n\n")) !== -1) {
|
||||||
|
const raw = acc.slice(0, i).trim();
|
||||||
|
acc = acc.slice(i + 2);
|
||||||
|
if (!raw || !raw.startsWith("data:")) continue;
|
||||||
|
const data = raw.slice(5).trim();
|
||||||
if (data === "[DONE]") {
|
if (data === "[DONE]") {
|
||||||
doneOnce();
|
doneOnce();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const j = JSON.parse(data);
|
const j = JSON.parse(data);
|
||||||
emit(j.choices?.[0]?.delta?.content ?? "", !!j.choices?.[0]?.finish_reason);
|
const delta = j.choices?.[0]?.delta?.content ?? "";
|
||||||
|
if (delta) {
|
||||||
|
buf += delta;
|
||||||
|
send({ t: "delta", id, data: delta });
|
||||||
|
}
|
||||||
|
const fin = j.choices?.[0]?.finish_reason;
|
||||||
|
if (fin) doneOnce();
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
doneOnce();
|
||||||
|
} catch (e) {
|
||||||
|
const aborted = e?.name === "AbortError" || /abort/i.test(String(e?.message || ""));
|
||||||
|
if (aborted) send({ t: "done", id, aborted: true });
|
||||||
|
else send({ t: "error", id, hint: hint(e?.message) });
|
||||||
|
} finally {
|
||||||
|
streams.delete(id);
|
||||||
}
|
}
|
||||||
doneOnce();
|
}
|
||||||
};
|
function stop(id) {
|
||||||
const openStream = (id, req) => {
|
const s = streams.get(id);
|
||||||
const ac = new AbortController();
|
if (!s) return;
|
||||||
let off = 0, buf = "", done = false;
|
try {
|
||||||
const record = { ctrl: ac, get off() {
|
s.ctrl.abort();
|
||||||
return off;
|
|
||||||
}, get buf() {
|
|
||||||
return buf;
|
|
||||||
}, get done() {
|
|
||||||
return done;
|
|
||||||
} };
|
|
||||||
streams.set(id, record);
|
|
||||||
const run = (async () => {
|
|
||||||
try {
|
|
||||||
const res = await fetch(req.url, { method: req.method || "POST", headers: req.headers || {}, body: JSON.stringify(req.body || {}), signal: ac.signal });
|
|
||||||
if (!res.ok) throw new Error(await res.text().catch(() => "") || "HTTP " + res.status);
|
|
||||||
await parseSSE(res, (delta, isDone) => {
|
|
||||||
if (delta) {
|
|
||||||
buf += delta;
|
|
||||||
off = buf.length;
|
|
||||||
send({ id, delta, off });
|
|
||||||
}
|
|
||||||
if (isDone && !done) {
|
|
||||||
done = true;
|
|
||||||
send({ id, done: true, off });
|
|
||||||
}
|
|
||||||
}, ac.signal);
|
|
||||||
} catch (e) {
|
|
||||||
send({ id, error: String(e?.message || e) });
|
|
||||||
} finally {
|
|
||||||
if (!done) {
|
|
||||||
done = true;
|
|
||||||
send({ id, done: true, off });
|
|
||||||
}
|
|
||||||
streams.delete(id);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
return run;
|
|
||||||
};
|
|
||||||
const cancelStream = (id) => {
|
|
||||||
const r = streams.get(id);
|
|
||||||
if (r) try {
|
|
||||||
r.ctrl.abort();
|
|
||||||
} catch {
|
} catch {
|
||||||
|
} finally {
|
||||||
|
streams.delete(id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
function replay(id, offset = 0) {
|
||||||
|
const s = streams.get(id);
|
||||||
|
if (!s) return;
|
||||||
|
const cur = s.buf(), remain = cur.slice(Math.max(0, offset));
|
||||||
|
if (remain) send({ t: "delta", id, data: remain });
|
||||||
|
if (s.done()) send({ t: "done", id });
|
||||||
|
}
|
||||||
|
bc = new BroadcastChannel(CH);
|
||||||
|
bc.onmessage = (e) => {
|
||||||
|
const m = e.data || {};
|
||||||
|
if (m.t === "hello") send({ t: "hello-ack" });
|
||||||
|
else if (m.t === "start" && m.id && m.payload) start(m.id, m.payload);
|
||||||
|
else if (m.t === "stop" && m.id) stop(m.id);
|
||||||
|
else if (m.t === "replay" && m.id) replay(m.id, m.offset | 0);
|
||||||
};
|
};
|
||||||
const replayStream = (id, from = 0) => {
|
|
||||||
const r = streams.get(id);
|
|
||||||
if (!r) return;
|
|
||||||
const s = r.buf || "", start = Math.max(0, from), CH = 16384;
|
|
||||||
for (let i = start; i < s.length; i += CH) {
|
|
||||||
const b = s.slice(i, Math.min(s.length, i + CH));
|
|
||||||
send({ id, delta: b, off: i + b.length });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.addEventListener("message", (e) => {
|
|
||||||
const msg = e.data || {}, port = e.ports?.[0];
|
|
||||||
const ok = (d) => port && port.postMessage(Object.assign({ ok: true }, d || {}));
|
|
||||||
const err = (m) => port && port.postMessage({ error: String(m) });
|
|
||||||
if (!msg.type) return;
|
|
||||||
if (msg.type === "hello") return ok({ stream: true });
|
|
||||||
if (msg.type === "stream-openrouter") {
|
|
||||||
const { id, req } = msg.data || {};
|
|
||||||
if (!id || !req) return err("bad args");
|
|
||||||
const p = openStream(id, req);
|
|
||||||
e.waitUntil(p);
|
|
||||||
return ok({});
|
|
||||||
}
|
|
||||||
if (msg.type === "stream-cancel") {
|
|
||||||
const { id } = msg.data || {};
|
|
||||||
if (!id) return err("bad args");
|
|
||||||
cancelStream(id);
|
|
||||||
return ok({});
|
|
||||||
}
|
|
||||||
if (msg.type === "stream-replay") {
|
|
||||||
const { id, from } = msg.data || {};
|
|
||||||
if (!id) return err("bad args");
|
|
||||||
replayStream(id, from | 0);
|
|
||||||
return ok({});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user