liminal-space / worker.js
Scadiva's picture
Deploy
bae6504 verified
Raw History Blame Contribute Delete
5.13 kB
import { pipeline, TextStreamer } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.3.3";
import { assessRisk, CRISIS_MESSAGE, WATCH_NOTE } from "./crisis.js";
// Preferred local models: 1.5B provides far better instruction following than 0.5B.
const PRIMARY_MODEL_ID = "onnx-community/Qwen2.5-1.5B-Instruct";
const FALLBACK_MODEL_ID = "onnx-community/Qwen2.5-0.5B-Instruct";
const CUSTOM_MODEL_ID = null; // e.g. "your-username/nd-solitude-qwen-onnx"
let ACTIVE_MODEL_ID = CUSTOM_MODEL_ID || PRIMARY_MODEL_ID;
function enforceDeclarativeLock(rawText) {
if (!rawText) return "";
const sentences = rawText.match(/[^.!?]+[.!?]+|[^.!?]+$/g) || [rawText];
const kept = [];
for (const s of sentences) {
const trimmed = s.trim();
if (trimmed.endsWith("?")) continue;
if (/^(why|how|what|when|where|who|could you|can you|would you|should you)\b/i.test(trimmed)) continue;
kept.push(trimmed);
}
return kept.join(" ");
}
class LocalSanctuaryEngine {
static generator = null;
static device = null;
static async pickDevice() {
try {
if (typeof navigator !== "undefined" && navigator.gpu) {
const adapter = await navigator.gpu.requestAdapter();
if (adapter) return "webgpu";
}
} catch (_) {
/* fall through to wasm */
}
return "wasm";
}
static async getGenerator(onProgress) {
if (!this.generator) {
this.device = await this.pickDevice();
try {
this.generator = await pipeline("text-generation", ACTIVE_MODEL_ID, {
device: this.device,
dtype: CUSTOM_MODEL_ID ? "q8" : this.device === "webgpu" ? "q4f16" : "q8",
progress_callback: onProgress,
});
} catch (err) {
// Fallback to smaller 0.5B model if 1.5B fails memory or network allocation
if (ACTIVE_MODEL_ID !== FALLBACK_MODEL_ID) {
console.warn(`Failed loading ${ACTIVE_MODEL_ID}, falling back to ${FALLBACK_MODEL_ID}:`, err);
ACTIVE_MODEL_ID = FALLBACK_MODEL_ID;
this.generator = await pipeline("text-generation", ACTIVE_MODEL_ID, {
device: this.device,
dtype: this.device === "webgpu" ? "q4f16" : "q8",
progress_callback: onProgress,
});
} else {
throw err;
}
}
}
return this.generator;
}
}
const PROMPTS = {
analytical:
"The assistant is an impersonal, objective analytical mirror running locally inside an offline vault. " +
"Never ask questions. Never use imperative verbs or suggest socializing. " +
"Provide brief, third-person structural observations about the concepts or patterns written, " +
"respecting total emotional distance and self-sufficiency.",
declarative:
"The assistant uses strictly low-demand declarative statements ('It appears...', 'One pattern here is...'). " +
"Ask zero questions and require zero reply. Validate the peace of solitude and staying put.",
solitude:
"The assistant reflects quietly on solitude, silence, and recovery. " +
"Never give advice, never ask questions, and never use commands. " +
"Offer gentle, grounded declarative observations about the stillness of the space.",
};
self.addEventListener("message", async (e) => {
const { type, text, mode } = e.data;
if (type === "INIT") {
try {
await LocalSanctuaryEngine.getGenerator((info) => {
self.postMessage({ status: "progress", info });
});
self.postMessage({ status: "ready", device: LocalSanctuaryEngine.device, model: ACTIVE_MODEL_ID });
} catch (err) {
self.postMessage({ status: "error", message: err.message });
}
return;
}
if (type === "REFLECT") {
const risk = assessRisk(text);
if (risk === "crisis") {
self.postMessage({ status: "crisis", text: CRISIS_MESSAGE });
return;
}
try {
const gen = await LocalSanctuaryEngine.getGenerator((info) => {
self.postMessage({ status: "progress", info });
});
const messages = [
{ role: "system", content: PROMPTS[mode] || PROMPTS.solitude },
{ role: "user", content: text },
];
let buffer = "";
const streamer = new TextStreamer(gen.tokenizer, {
skip_prompt: true,
skip_special_tokens: true,
callback_function: (tok) => {
buffer += tok;
const clean = enforceDeclarativeLock(buffer);
self.postMessage({ status: "stream", text: clean || buffer.replace(/\?/g, ".") });
},
});
await gen(messages, {
max_new_tokens: 120,
temperature: 0.35,
do_sample: true,
top_p: 0.9,
streamer,
});
const finalClean = enforceDeclarativeLock(buffer) || buffer.replace(/\?/g, ".");
if (risk === "watch") {
self.postMessage({ status: "stream", text: finalClean + "\n\n" + WATCH_NOTE });
} else {
self.postMessage({ status: "stream", text: finalClean });
}
self.postMessage({ status: "done" });
} catch (err) {
self.postMessage({ status: "error", message: err.message });
}
}
});