@cfasim-ui/pyodide 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/pyodide.worker.ts +38 -17
- package/src/useModel.ts +12 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cfasim-ui/pyodide",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pyodide (Python-in-browser) integration for cfasim-ui",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"pyodide": "^0.29.3",
|
|
24
|
-
"@cfasim-ui/shared": "0.1.
|
|
24
|
+
"@cfasim-ui/shared": "0.1.9"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"vue": "^3.5.0"
|
package/src/pyodide.worker.ts
CHANGED
|
@@ -14,7 +14,6 @@ interface WorkerMessage {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
let wheelMap: Record<string, string> = {};
|
|
17
|
-
const loadedModules = new Set<string>();
|
|
18
17
|
|
|
19
18
|
const baseUrl = import.meta.env.BASE_URL ?? "/";
|
|
20
19
|
|
|
@@ -44,28 +43,43 @@ const pyodideReadyPromise = (async () => {
|
|
|
44
43
|
return pyodide;
|
|
45
44
|
})();
|
|
46
45
|
|
|
47
|
-
let
|
|
46
|
+
let installPromise: Promise<void> | null = null;
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
function installAllWheels(): Promise<void> {
|
|
49
|
+
if (!installPromise) {
|
|
50
|
+
installPromise = (async () => {
|
|
51
|
+
const urls = Object.values(wheelMap).map(
|
|
52
|
+
(f) => `${self.location.origin}${baseUrl}${f}`,
|
|
53
|
+
);
|
|
54
|
+
if (urls.length > 0) {
|
|
55
|
+
await micropip.install(urls);
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
installPromise.catch(() => {
|
|
59
|
+
installPromise = null;
|
|
60
|
+
});
|
|
57
61
|
}
|
|
62
|
+
return installPromise;
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
const modulePromises = new Map<string, Promise<void>>();
|
|
66
|
+
|
|
67
|
+
function ensureModule(
|
|
61
68
|
pyodide: Awaited<typeof pyodideReadyPromise>,
|
|
62
69
|
moduleName: string,
|
|
63
|
-
) {
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
if (!modulePromises.has(moduleName)) {
|
|
72
|
+
if (!wheelMap[moduleName]) throw new Error(`Unknown module: ${moduleName}`);
|
|
73
|
+
const promise = (async () => {
|
|
74
|
+
await installAllWheels();
|
|
75
|
+
pyodide.pyimport(moduleName);
|
|
76
|
+
})();
|
|
77
|
+
promise.catch(() => {
|
|
78
|
+
modulePromises.delete(moduleName);
|
|
79
|
+
});
|
|
80
|
+
modulePromises.set(moduleName, promise);
|
|
81
|
+
}
|
|
82
|
+
return modulePromises.get(moduleName)!;
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
// Map Python struct format characters to TypedArray constructors
|
|
@@ -122,6 +136,13 @@ function convertModelOutputs(jsResult: any): ModelOutputsWire | null {
|
|
|
122
136
|
if ((buf as any).destroy) (buf as any).destroy();
|
|
123
137
|
} else if (buf instanceof ArrayBuffer) {
|
|
124
138
|
buffers.push(buf);
|
|
139
|
+
} else if (ArrayBuffer.isView(buf)) {
|
|
140
|
+
buffers.push(
|
|
141
|
+
buf.buffer.slice(
|
|
142
|
+
buf.byteOffset,
|
|
143
|
+
buf.byteOffset + buf.byteLength,
|
|
144
|
+
) as ArrayBuffer,
|
|
145
|
+
);
|
|
125
146
|
}
|
|
126
147
|
}
|
|
127
148
|
|
package/src/useModel.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, toValue, watch } from "vue";
|
|
1
|
+
import { ref, toRaw, toValue, watch } from "vue";
|
|
2
2
|
import type { MaybeRef } from "vue";
|
|
3
3
|
import type { ModelOutput } from "@cfasim-ui/shared";
|
|
4
4
|
import { asyncRunPython, loadModule } from "./pyodideWorkerApi.js";
|
|
@@ -20,9 +20,14 @@ export function useModel<T = unknown>(moduleName: string) {
|
|
|
20
20
|
await loaded;
|
|
21
21
|
const argNames = context ? Object.keys(context) : [];
|
|
22
22
|
const callArgs = argNames.join(", ");
|
|
23
|
+
const plainContext = context
|
|
24
|
+
? Object.fromEntries(
|
|
25
|
+
Object.entries(context).map(([k, v]) => [k, toRaw(v)]),
|
|
26
|
+
)
|
|
27
|
+
: undefined;
|
|
23
28
|
const response = await asyncRunPython(
|
|
24
29
|
`import ${moduleName}\n${moduleName}.${fn}(${callArgs})`,
|
|
25
|
-
|
|
30
|
+
plainContext,
|
|
26
31
|
);
|
|
27
32
|
if (response.error) {
|
|
28
33
|
error.value = response.error;
|
|
@@ -51,11 +56,14 @@ export function useModel<T = unknown>(moduleName: string) {
|
|
|
51
56
|
outputsError.value = undefined;
|
|
52
57
|
try {
|
|
53
58
|
await loaded;
|
|
54
|
-
const
|
|
59
|
+
const plain = Object.fromEntries(
|
|
60
|
+
Object.entries(p).map(([k, v]) => [k, toRaw(v)]),
|
|
61
|
+
);
|
|
62
|
+
const argNames = Object.keys(plain);
|
|
55
63
|
const callArgs = argNames.join(", ");
|
|
56
64
|
const response = await asyncRunPython(
|
|
57
65
|
`import ${moduleName}\n${moduleName}.${fn}(${callArgs})`,
|
|
58
|
-
|
|
66
|
+
plain,
|
|
59
67
|
);
|
|
60
68
|
if (response.error) {
|
|
61
69
|
outputsError.value = response.error;
|