// AksharaLP Space — engine host, shared by the Web Worker (js/worker.js) and the main-thread fallback in js/app.js. // Two-tier load: the small core (model + reranker) first, so typing works immediately; then the dictionary pack // (lexicon + sentence LM), read from the Cache API after the first visit. If the pack cannot be fetched, or does not // arrive within DICT_TIMEOUT_MS, the engine keeps running core-only. // // `search` is the page's query string. On a private Hugging Face Space the page is opened as index.html?__sign= // inside a cross-site iframe, where the SameSite=Lax auth cookie is not sent; same-origin requests are authorised only // through their Referer. A worker's (and a module's) requests carry the worker's / module's own URL as Referer, so // the query is forwarded onto those URLs. Cross-origin requests (the CDN) only ever see the origin. const DICT_TIMEOUT_MS = 180000; export function startHost(post, search = "") { let engine = null; const q = new URLSearchParams(search); const fwd = new URLSearchParams(search); fwd.delete("dict"); const qs = fwd.toString() ? "?" + fwd.toString() : ""; const ready = (async () => { try { const { default: BhashaCore } = await import("./aksharalp.mjs" + qs); const base = new URL("../model/", import.meta.url).href; engine = await BhashaCore.load(base, { dict: false, onProgress: (file) => post({ type: "progress", file }) }); const t0 = performance.now(); engine.transliterate("main ghar ja raha hoon", { k: 5 }); post({ type: "ready", info: engine.info(), loadMs: engine.loadMs, warmMs: performance.now() - t0, note: engine.manifest && engine.manifest.note, name: engine.manifest && engine.manifest.name }); if (q.get("dict") === "0") { post({ type: "dict", ok: false, skipped: true, info: engine.info() }); return; } const t1 = performance.now(); let src = null, timer; const timeout = new Promise((res) => { timer = setTimeout(() => res("timeout"), DICT_TIMEOUT_MS); }); const ok = await Promise.race([engine.loadDict({ onProgress: (file, from) => { src = from; post({ type: "progress", file: "dictionary/" + file, from }); } }), timeout]); clearTimeout(timer); if (ok === "timeout") { post({ type: "dict", ok: false, error: `dictionary pack did not arrive within ${DICT_TIMEOUT_MS / 1000} s; running core-only`, info: engine.info() }); return; } if (ok) engine.transliterate("main ghar ja raha hoon", { k: 5 }); post({ type: "dict", ok, from: src, ms: performance.now() - t1, error: engine.dictError, info: engine.info() }); } catch (e) { post({ type: "error", message: String(e && e.message || e) }); } })(); return (data) => { if (!engine) return post({ type: "error", id: data.id, message: "model not loaded" }); try { if (data.type === "run") { const res = engine.transliterate(data.text, data.opts || {}); post({ type: "result", id: data.id, tag: data.tag, res }); } else if (data.type === "batch") { const out = data.items.map((it) => engine.transliterate(it.text, it.opts || {})); post({ type: "batch", id: data.id, out }); } } catch (e) { post({ type: "error", id: data.id, message: String(e && e.message || e) }); } }; }