Spaces:
Running
Running
File size: 3,711 Bytes
0390c03 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | /* Python (Pyodide) and the whole verification pipeline run here, off the main thread. */
let py = null, hadithReady = null;
const post = (m) => self.postMessage(m);
const status = (text, step) => post({ type: "status", text, step });
async function fetchBytes(url, onProgress) {
let cache = null;
try { cache = await caches.open("icv-v2"); const hit = await cache.match(url); if (hit) return new Uint8Array(await hit.arrayBuffer()); } catch (e) { cache = null; }
const response = await fetch(url);
if (!response.ok) throw new Error("تعذّر تحميل " + url + " (" + response.status + ")");
if (cache) { try { await cache.put(url, response.clone()); } catch (e) { /* optimisation only */ } }
const total = Number(response.headers.get("Content-Length")) || 0;
if (!response.body || !onProgress) return new Uint8Array(await response.arrayBuffer());
const reader = response.body.getReader(), chunks = []; let received = 0;
for (;;) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); received += value.length; onProgress(received, total); }
const bytes = new Uint8Array(received); let offset = 0;
for (const c of chunks) { bytes.set(c, offset); offset += c.length; }
return bytes;
}
// Accept both layouts: files inside folders (index/, demo/) or uploaded flat next to index.html.
async function fetchAny(file, base, onProgress) {
let lastError = null;
for (const path of [file, file.split("/").pop()]) {
try { return await fetchBytes(new URL(path, base).href, onProgress); } catch (e) { lastError = e; }
}
throw lastError;
}
async function boot(m) {
status("جارٍ تحميل بيئة بايثون…", 1);
importScripts("https://cdn.jsdelivr.net/pyodide/v" + m.pyodideVersion + "/full/pyodide.js");
py = await loadPyodide();
status("جارٍ تحميل الكود وفهرس القرآن…", 2);
for (const dir of ["/app", "/app/index", "/app/demo", "/app/data"]) py.FS.mkdir(dir);
for (const file of m.files) py.FS.writeFile("/app/" + file, await fetchAny(file, m.base));
py.runPython("import sys; sys.path.insert(0, '/app')");
py.runPython("from app import get_pipeline, verify_text, verify_generated_answer, analyze_benchmark, detect_spans, verify_given_spans; get_pipeline()");
post({ type: "ready" });
hadithReady = loadHadith(m); // background; verification waits for it
}
async function loadHadith(m) {
const file = m.lazy[0];
const bytes = await fetchAny(file, m.base, (got, total) => {
const mb = (got / 1048576).toFixed(1), of = total ? " / " + (total / 1048576).toFixed(1) : "";
post({ type: "progress", got, total });
status("جارٍ تحميل كتب الحديث… " + mb + of + " ميغابايت", 3);
});
py.FS.writeFile("/app/" + file, bytes);
status("جارٍ تجهيز كتب الحديث…", 3);
py.runPython("get_pipeline().retriever.warm()");
post({ type: "hadith" });
}
self.onmessage = async (event) => {
const m = event.data;
if (m.type === "boot") {
try { await boot(m); } catch (e) { post({ type: "error", text: String((e && e.message) || e) }); }
return;
}
try {
await hadithReady;
const call = (name, ...args) => py.globals.get(name)(...args);
let out;
if (m.type === "verify") out = call(m.generated ? "verify_generated_answer" : "verify_text", m.text);
else if (m.type === "detect") out = call("detect_spans", m.text);
else if (m.type === "verify_spans") out = call("verify_given_spans", m.text, m.spans);
else if (m.type === "benchmark") out = call("analyze_benchmark", m.text);
post({ type: "result", id: m.id, value: out });
} catch (e) { post({ type: "result", id: m.id, value: null }); }
};
|