mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-16 18:44:47 +00:00
101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
// ifc_worker.js (MODULE WORKER)
|
|
import { loadPyodide } from "https://cdn.jsdelivr.net/pyodide/v0.29.3/full/pyodide.mjs";
|
|
|
|
let pyodide = null;
|
|
let callToolPy = null;
|
|
let initPromise = null;
|
|
|
|
function ok(id, extra = {}, transfer = []) {
|
|
self.postMessage({ id, ok: true, ...extra }, transfer);
|
|
}
|
|
function fail(id, error) {
|
|
self.postMessage({ id, ok: false, error: String(error?.message || error) });
|
|
}
|
|
|
|
async function ensurePyodide() {
|
|
if (initPromise) return initPromise;
|
|
|
|
initPromise = (async () => {
|
|
// Passing indexURL avoids some environments failing to infer it from the module URL. :contentReference[oaicite:3]{index=3}
|
|
pyodide = await loadPyodide({
|
|
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.29.3/full/",
|
|
});
|
|
|
|
await pyodide.loadPackage("micropip");
|
|
await pyodide.loadPackage("numpy");
|
|
await pyodide.loadPackage("shapely");
|
|
await pyodide.loadPackage("typing-extensions");
|
|
|
|
const micropip = pyodide.pyimport("micropip");
|
|
micropip.install("python-dateutil")
|
|
|
|
const wheelUrl = "https://ifcopenshell.github.io/wasm-wheels/ifcopenshell-0.8.5-cp313-cp313-pyodide_2025_0_wasm32.whl";
|
|
|
|
await micropip.install(wheelUrl);
|
|
|
|
await micropip.install([
|
|
"./dist/ifcquery-0.8.5-py3-none-any.whl",
|
|
"./dist/ifcedit-0.8.5-py3-none-any.whl",
|
|
"./dist/ifcopenshell_mcp-0.8.5-py3-none-any.whl",
|
|
"./dist/lark-1.3.1-py3-none-any.whl",
|
|
"./dist/isodate-0.7.2-py3-none-any.whl",
|
|
])
|
|
await pyodide.runPythonAsync(`
|
|
from ifcmcp.embedded import call_tool as _call_tool
|
|
`);
|
|
callToolPy = pyodide.globals.get("_call_tool");
|
|
})();
|
|
|
|
return initPromise;
|
|
}
|
|
|
|
function callTool(name, args) {
|
|
const pyArgs = pyodide.toPy(args);
|
|
const res = callToolPy(name, pyArgs);
|
|
pyArgs.destroy();
|
|
const resJs = res.toJs({ dict_converter: Object.fromEntries });
|
|
res.destroy();
|
|
return resJs;
|
|
}
|
|
|
|
self.onmessage = async (ev) => {
|
|
const { id, type, payload } = ev.data || {};
|
|
try {
|
|
if (type === "init") {
|
|
await ensurePyodide();
|
|
ok(id, { result: "ok" });
|
|
return;
|
|
}
|
|
|
|
await ensurePyodide();
|
|
|
|
if (type === "loadIfc") {
|
|
const { filename, bytes } = payload;
|
|
const path = `/tmp/${filename || "model.ifc"}`;
|
|
pyodide.FS.mkdirTree("/tmp");
|
|
pyodide.FS.writeFile(path, new Uint8Array(bytes));
|
|
const result = callTool("ifc_load", { path });
|
|
ok(id, { result });
|
|
return;
|
|
}
|
|
|
|
if (type === "exportIfc") {
|
|
const path = "/tmp/export.ifc";
|
|
const result = callTool("ifc_save", { path });
|
|
const data = pyodide.FS.readFile(path);
|
|
ok(id, { result, filename: "export.ifc", bytes: data }, [data.buffer]);
|
|
return;
|
|
}
|
|
|
|
if (type === "toolCall") {
|
|
const { name, args } = payload;
|
|
const result = callTool(name, args || {});
|
|
ok(id, { result });
|
|
return;
|
|
}
|
|
|
|
throw new Error(`Unknown message type: ${type}`);
|
|
} catch (e) {
|
|
fail(id, e);
|
|
}
|
|
}; |