wrapture 0.0.2 β 0.1.0
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/.github/workflows/check.yml +8 -1
- package/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/api/README.md +3 -1
- package/api/utils/check-deps.md +61 -0
- package/api/utils/convert.md +5 -5
- package/api/utils/generate-wrapper.md +4 -4
- package/api/utils/log-level.md +161 -0
- package/api/wrapture.md +1 -1
- package/bin/wrapture.js +218 -27
- package/package.json +1 -1
- package/python/convert.py +2 -2
- package/src/utils/check-deps.ts +55 -0
- package/src/utils/convert.ts +16 -15
- package/src/utils/generate-wrapper.ts +9 -6
- package/src/utils/log-level.ts +31 -0
- package/src/wrapture.ts +39 -11
|
@@ -48,6 +48,13 @@ jobs:
|
|
|
48
48
|
uses: actions/setup-node@v4
|
|
49
49
|
with:
|
|
50
50
|
node-version: '>=22.8.0'
|
|
51
|
+
- uses: actions/setup-python@v4
|
|
52
|
+
with:
|
|
53
|
+
python-version: '3.10'
|
|
54
|
+
- name: Install Python dependencies
|
|
55
|
+
run: |
|
|
56
|
+
python3 -m pip install --upgrade pip
|
|
57
|
+
pip install torch onnx onnxsim onnxruntime
|
|
51
58
|
- name: Install dependencies
|
|
52
59
|
run: | # Install and link dependencies
|
|
53
60
|
npm i
|
|
@@ -69,4 +76,4 @@ jobs:
|
|
|
69
76
|
- uses: jayqi/failed-build-issue-action@v1.2
|
|
70
77
|
with:
|
|
71
78
|
github-token: ${{ secrets.GH_TOKEN }}
|
|
72
|
-
label-name: 'problems: build failed'
|
|
79
|
+
label-name: 'problems: π build failed'
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0](https://github.com/phun-ky/wrapture/compare/0.0.3...0.1.0) (2025-05-15)
|
|
4
|
+
|
|
5
|
+
### Tasks
|
|
6
|
+
|
|
7
|
+
* π€ add `bin/` to `.gitignore` ([a90b288](https://github.com/phun-ky/wrapture/commit/a90b2880a6179010b6133f719eb7696759e6ac06))
|
|
8
|
+
* π€ Delete file from bin ([b707abd](https://github.com/phun-ky/wrapture/commit/b707abddd989c43da70bf91512d75e752c18456c))
|
|
9
|
+
* π€ Remove old dep imports ([819e9e4](https://github.com/phun-ky/wrapture/commit/819e9e439f0bbf50383038db2cded3d3c167e3f3))
|
|
10
|
+
* π€ Use correct label ([3d6acf0](https://github.com/phun-ky/wrapture/commit/3d6acf0311f18e9e2d90b4a129f0dc7cae9b955c))
|
|
11
|
+
|
|
12
|
+
### Feature
|
|
13
|
+
|
|
14
|
+
* πΈ Add `--logLevel`-option and clean up messages ([c93f4ef](https://github.com/phun-ky/wrapture/commit/c93f4ef0570d4fe7501776f2fbce1ed362e048a7))
|
|
15
|
+
* πΈ Check for correct dependencies ([28d1d4d](https://github.com/phun-ky/wrapture/commit/28d1d4def395c700285caf82139e8b0786cc4855))
|
|
16
|
+
|
|
17
|
+
### Bug
|
|
18
|
+
|
|
19
|
+
* π Remove outtdated python module ([0b58d3c](https://github.com/phun-ky/wrapture/commit/0b58d3cc5c2758b606333e011766a3ed91fbfa74))
|
|
20
|
+
|
|
21
|
+
### Refactoring
|
|
22
|
+
|
|
23
|
+
* π‘ Adjust cli interface ([ddc80b9](https://github.com/phun-ky/wrapture/commit/ddc80b9d96f11133c2aa4e26ffcde40f316f12a8))
|
|
24
|
+
|
|
25
|
+
## [0.0.3](https://github.com/phun-ky/wrapture/compare/0.0.2...0.0.3) (2025-05-14)
|
|
26
|
+
|
|
27
|
+
### Bug
|
|
28
|
+
|
|
29
|
+
* π Python env ([36d0a30](https://github.com/phun-ky/wrapture/commit/36d0a302aebfabf9860f7cc5c70bc8151b221632))
|
|
30
|
+
|
|
3
31
|
## [0.0.2](https://github.com/phun-ky/wrapture/compare/0.0.1...0.0.2) (2025-05-14)
|
|
4
32
|
|
|
5
33
|
### Documentation
|
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Install Python if you donβt have it: π <https://www.python.org/downloads/>
|
|
|
62
62
|
### Install required Python packages
|
|
63
63
|
|
|
64
64
|
```shell-session
|
|
65
|
-
python3 -m pip install torch onnx onnxsim onnxruntime
|
|
65
|
+
python3 -m pip install torch onnx onnxsim onnxruntime
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
Check your installation:
|
package/api/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# wrapture API documentation
|
|
2
2
|
|
|
3
|
-
> Last updated 2025-05-
|
|
3
|
+
> Last updated 2025-05-15T10:00:06.699Z
|
|
4
4
|
|
|
5
5
|
## Modules
|
|
6
6
|
|
|
7
|
+
- [utils/check-deps](utils/check-deps.md)
|
|
7
8
|
- [utils/convert](utils/convert.md)
|
|
8
9
|
- [utils/generate-wrapper](utils/generate-wrapper.md)
|
|
10
|
+
- [utils/log-level](utils/log-level.md)
|
|
9
11
|
- [wrapture](wrapture.md)
|
|
10
12
|
|
|
11
13
|
---
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[wrapture](../README.md) / utils/check-deps
|
|
2
|
+
|
|
3
|
+
# utils/check-deps
|
|
4
|
+
|
|
5
|
+
> Last updated 2025-05-15T10:00:06.852Z
|
|
6
|
+
|
|
7
|
+
## Functions
|
|
8
|
+
|
|
9
|
+
### checkPythonAvailable()
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
function checkPythonAvailable(): void;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Defined in:
|
|
16
|
+
[utils/check-deps.ts:11](https://github.com/phun-ky/wrapture/blob/main/src/utils/check-deps.ts#L11)
|
|
17
|
+
|
|
18
|
+
#### Returns
|
|
19
|
+
|
|
20
|
+
`void`
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### checkPythonDeps()
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
function checkPythonDeps(): void;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Defined in:
|
|
31
|
+
[utils/check-deps.ts:23](https://github.com/phun-ky/wrapture/blob/main/src/utils/check-deps.ts#L23)
|
|
32
|
+
|
|
33
|
+
#### Returns
|
|
34
|
+
|
|
35
|
+
`void`
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
**Contributing**
|
|
40
|
+
|
|
41
|
+
Want to contribute? Please read the
|
|
42
|
+
[CONTRIBUTING.md](https://github.com/phun-ky/wrapture/blob/main/CONTRIBUTING.md)
|
|
43
|
+
and
|
|
44
|
+
[CODE_OF_CONDUCT.md](https://github.com/phun-ky/wrapture/blob/main/CODE_OF_CONDUCT.md)
|
|
45
|
+
|
|
46
|
+
**Sponsor me**
|
|
47
|
+
|
|
48
|
+
I'm an Open Source evangelist, creating stuff that does not exist yet to help
|
|
49
|
+
get rid of secondary activities and to enhance systems already in place, be it
|
|
50
|
+
documentation or web sites.
|
|
51
|
+
|
|
52
|
+
The sponsorship is an unique opportunity to alleviate more hours for me to
|
|
53
|
+
maintain my projects, create new ones and contribute to the large community
|
|
54
|
+
we're all part of :)
|
|
55
|
+
|
|
56
|
+
[Support me on GitHub Sponsors](https://github.com/sponsors/phun-ky).
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
This project created by [Alexander Vassbotn RΓΈyne-Helgesen](http://phun-ky.net)
|
|
61
|
+
is licensed under a [MIT License](https://choosealicense.com/licenses/mit/).
|
package/api/utils/convert.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# utils/convert
|
|
4
4
|
|
|
5
|
-
> Last updated 2025-05-
|
|
5
|
+
> Last updated 2025-05-15T10:00:06.925Z
|
|
6
6
|
|
|
7
7
|
## Interfaces
|
|
8
8
|
|
|
9
9
|
### ConvertOptionsInterface
|
|
10
10
|
|
|
11
11
|
Defined in:
|
|
12
|
-
[utils/convert.ts:
|
|
12
|
+
[utils/convert.ts:12](https://github.com/phun-ky/wrapture/blob/main/src/utils/convert.ts#L12)
|
|
13
13
|
|
|
14
14
|
Options for the [convert](#convert) function.
|
|
15
15
|
|
|
@@ -17,8 +17,8 @@ Options for the [convert](#convert) function.
|
|
|
17
17
|
|
|
18
18
|
| Property | Type | Description | Defined in |
|
|
19
19
|
| --------------------------------- | --------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
20
|
-
| <a id="format"></a> `format?` | `string` | The output format for the converted model (e.g., 'onnx'). Defaults to 'onnx' if not provided. | [utils/convert.ts:
|
|
21
|
-
| <a id="quantize"></a> `quantize?` | `boolean` | Whether to apply quantization to the model. | [utils/convert.ts:
|
|
20
|
+
| <a id="format"></a> `format?` | `string` | The output format for the converted model (e.g., 'onnx'). Defaults to 'onnx' if not provided. | [utils/convert.ts:17](https://github.com/phun-ky/wrapture/blob/main/src/utils/convert.ts#L17) |
|
|
21
|
+
| <a id="quantize"></a> `quantize?` | `boolean` | Whether to apply quantization to the model. | [utils/convert.ts:22](https://github.com/phun-ky/wrapture/blob/main/src/utils/convert.ts#L22) |
|
|
22
22
|
|
|
23
23
|
## Functions
|
|
24
24
|
|
|
@@ -29,7 +29,7 @@ function convert(inputPath, outputDir, opts): Promise<void>;
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Defined in:
|
|
32
|
-
[utils/convert.ts:
|
|
32
|
+
[utils/convert.ts:49](https://github.com/phun-ky/wrapture/blob/main/src/utils/convert.ts#L49)
|
|
33
33
|
|
|
34
34
|
Converts a machine learning model to ONNX or another supported format by
|
|
35
35
|
delegating to a Python script (`convert.py`).
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# utils/generate-wrapper
|
|
4
4
|
|
|
5
|
-
> Last updated 2025-05-
|
|
5
|
+
> Last updated 2025-05-15T10:00:06.977Z
|
|
6
6
|
|
|
7
7
|
## Interfaces
|
|
8
8
|
|
|
9
9
|
### GenerateWrapperOptionsInterface
|
|
10
10
|
|
|
11
11
|
Defined in:
|
|
12
|
-
[utils/generate-wrapper.ts:
|
|
12
|
+
[utils/generate-wrapper.ts:10](https://github.com/phun-ky/wrapture/blob/main/src/utils/generate-wrapper.ts#L10)
|
|
13
13
|
|
|
14
14
|
Options for generating ONNX wrapper files.
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ Options for generating ONNX wrapper files.
|
|
|
17
17
|
|
|
18
18
|
| Property | Type | Description | Defined in |
|
|
19
19
|
| ------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
20
|
-
| <a id="backend"></a> `backend` | `string` | The backend to use for inference. This affects the model file used. If set to `'wasm'`, the generated wrapper will load `model_quant.onnx`, otherwise it will load `model.onnx`. | [utils/generate-wrapper.ts:
|
|
20
|
+
| <a id="backend"></a> `backend` | `string` | The backend to use for inference. This affects the model file used. If set to `'wasm'`, the generated wrapper will load `model_quant.onnx`, otherwise it will load `model.onnx`. | [utils/generate-wrapper.ts:16](https://github.com/phun-ky/wrapture/blob/main/src/utils/generate-wrapper.ts#L16) |
|
|
21
21
|
|
|
22
22
|
## Functions
|
|
23
23
|
|
|
@@ -28,7 +28,7 @@ function generateWrapper(outputDir, opts): Promise<void>;
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Defined in:
|
|
31
|
-
[utils/generate-wrapper.ts:
|
|
31
|
+
[utils/generate-wrapper.ts:40](https://github.com/phun-ky/wrapture/blob/main/src/utils/generate-wrapper.ts#L40)
|
|
32
32
|
|
|
33
33
|
Generates a TypeScript wrapper and type definition file (`wrapped.ts` and
|
|
34
34
|
`wrapped.d.ts`) for use with `onnxruntime-web`, including utility functions like
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
[wrapture](../README.md) / utils/log-level
|
|
2
|
+
|
|
3
|
+
# utils/log-level
|
|
4
|
+
|
|
5
|
+
> Last updated 2025-05-15T10:00:07.021Z
|
|
6
|
+
|
|
7
|
+
## Type Aliases
|
|
8
|
+
|
|
9
|
+
### LogLevelType
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
type LogLevelType = 'silent' | 'error' | 'warn' | 'info' | 'debug';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Defined in:
|
|
16
|
+
[utils/log-level.ts:2](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L2)
|
|
17
|
+
|
|
18
|
+
## Variables
|
|
19
|
+
|
|
20
|
+
### log
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const log: {
|
|
24
|
+
debug: (...args) => false | void;
|
|
25
|
+
error: (...args) => false | void;
|
|
26
|
+
info: (...args) => false | void;
|
|
27
|
+
warn: (...args) => false | void;
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Defined in:
|
|
32
|
+
[utils/log-level.ts:22](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L22)
|
|
33
|
+
|
|
34
|
+
#### Type declaration
|
|
35
|
+
|
|
36
|
+
<table>
|
|
37
|
+
<thead>
|
|
38
|
+
<tr>
|
|
39
|
+
<th>Name</th>
|
|
40
|
+
<th>Type</th>
|
|
41
|
+
<th>Defined in</th>
|
|
42
|
+
</tr>
|
|
43
|
+
</thead>
|
|
44
|
+
<tbody>
|
|
45
|
+
<tr>
|
|
46
|
+
<td>
|
|
47
|
+
|
|
48
|
+
<a id="debug"></a> `debug()`
|
|
49
|
+
|
|
50
|
+
</td>
|
|
51
|
+
<td>
|
|
52
|
+
|
|
53
|
+
(...`args`) => `false` | `void`
|
|
54
|
+
|
|
55
|
+
</td>
|
|
56
|
+
<td>
|
|
57
|
+
|
|
58
|
+
[utils/log-level.ts:23](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L23)
|
|
59
|
+
|
|
60
|
+
</td>
|
|
61
|
+
</tr>
|
|
62
|
+
<tr>
|
|
63
|
+
<td>
|
|
64
|
+
|
|
65
|
+
<a id="error"></a> `error()`
|
|
66
|
+
|
|
67
|
+
</td>
|
|
68
|
+
<td>
|
|
69
|
+
|
|
70
|
+
(...`args`) => `false` | `void`
|
|
71
|
+
|
|
72
|
+
</td>
|
|
73
|
+
<td>
|
|
74
|
+
|
|
75
|
+
[utils/log-level.ts:29](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L29)
|
|
76
|
+
|
|
77
|
+
</td>
|
|
78
|
+
</tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td>
|
|
81
|
+
|
|
82
|
+
<a id="info"></a> `info()`
|
|
83
|
+
|
|
84
|
+
</td>
|
|
85
|
+
<td>
|
|
86
|
+
|
|
87
|
+
(...`args`) => `false` | `void`
|
|
88
|
+
|
|
89
|
+
</td>
|
|
90
|
+
<td>
|
|
91
|
+
|
|
92
|
+
[utils/log-level.ts:25](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L25)
|
|
93
|
+
|
|
94
|
+
</td>
|
|
95
|
+
</tr>
|
|
96
|
+
<tr>
|
|
97
|
+
<td>
|
|
98
|
+
|
|
99
|
+
<a id="warn"></a> `warn()`
|
|
100
|
+
|
|
101
|
+
</td>
|
|
102
|
+
<td>
|
|
103
|
+
|
|
104
|
+
(...`args`) => `false` | `void`
|
|
105
|
+
|
|
106
|
+
</td>
|
|
107
|
+
<td>
|
|
108
|
+
|
|
109
|
+
[utils/log-level.ts:27](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L27)
|
|
110
|
+
|
|
111
|
+
</td>
|
|
112
|
+
</tr>
|
|
113
|
+
</tbody>
|
|
114
|
+
</table>
|
|
115
|
+
|
|
116
|
+
## Functions
|
|
117
|
+
|
|
118
|
+
### setLogLevel()
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
function setLogLevel(level): void;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Defined in:
|
|
125
|
+
[utils/log-level.ts:14](https://github.com/phun-ky/wrapture/blob/main/src/utils/log-level.ts#L14)
|
|
126
|
+
|
|
127
|
+
#### Parameters
|
|
128
|
+
|
|
129
|
+
| Parameter | Type |
|
|
130
|
+
| --------- | ------------------------------- |
|
|
131
|
+
| `level` | [`LogLevelType`](#logleveltype) |
|
|
132
|
+
|
|
133
|
+
#### Returns
|
|
134
|
+
|
|
135
|
+
`void`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
**Contributing**
|
|
140
|
+
|
|
141
|
+
Want to contribute? Please read the
|
|
142
|
+
[CONTRIBUTING.md](https://github.com/phun-ky/wrapture/blob/main/CONTRIBUTING.md)
|
|
143
|
+
and
|
|
144
|
+
[CODE_OF_CONDUCT.md](https://github.com/phun-ky/wrapture/blob/main/CODE_OF_CONDUCT.md)
|
|
145
|
+
|
|
146
|
+
**Sponsor me**
|
|
147
|
+
|
|
148
|
+
I'm an Open Source evangelist, creating stuff that does not exist yet to help
|
|
149
|
+
get rid of secondary activities and to enhance systems already in place, be it
|
|
150
|
+
documentation or web sites.
|
|
151
|
+
|
|
152
|
+
The sponsorship is an unique opportunity to alleviate more hours for me to
|
|
153
|
+
maintain my projects, create new ones and contribute to the large community
|
|
154
|
+
we're all part of :)
|
|
155
|
+
|
|
156
|
+
[Support me on GitHub Sponsors](https://github.com/sponsors/phun-ky).
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
This project created by [Alexander Vassbotn RΓΈyne-Helgesen](http://phun-ky.net)
|
|
161
|
+
is licensed under a [MIT License](https://choosealicense.com/licenses/mit/).
|
package/api/wrapture.md
CHANGED
package/bin/wrapture.js
CHANGED
|
@@ -3,25 +3,197 @@
|
|
|
3
3
|
// src/wrapture.ts
|
|
4
4
|
import chalk2 from "chalk";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
+
import ora from "ora";
|
|
6
7
|
import { existsSync } from "node:fs";
|
|
7
8
|
import path3 from "node:path";
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
+
// package.json
|
|
11
|
+
var package_default = {
|
|
12
|
+
name: "wrapture",
|
|
13
|
+
version: "0.1.0",
|
|
14
|
+
description: "Wrapture lets you go from a Python-trained model to deployable JavaScript with a single command. It generates TypeScript bindings and a Web/Node-compatible wrapper, using WebGPU/WASM-ready ONNX runtimes.",
|
|
15
|
+
keywords: [
|
|
16
|
+
"onnx",
|
|
17
|
+
"pytorch",
|
|
18
|
+
"torch",
|
|
19
|
+
"model exporter",
|
|
20
|
+
"onnx export",
|
|
21
|
+
"onnx runtime",
|
|
22
|
+
"onnx to javascript",
|
|
23
|
+
"machine learning",
|
|
24
|
+
"ml model conversion",
|
|
25
|
+
"typescript",
|
|
26
|
+
"javascript",
|
|
27
|
+
"cli tool",
|
|
28
|
+
"webgpu",
|
|
29
|
+
"wasm",
|
|
30
|
+
"onnx simplifier",
|
|
31
|
+
"onnx quantization",
|
|
32
|
+
"deep learning",
|
|
33
|
+
"model conversion",
|
|
34
|
+
"wrapture",
|
|
35
|
+
"loadModel",
|
|
36
|
+
"predict"
|
|
37
|
+
],
|
|
38
|
+
homepage: "https://github.com/phun-ky/wrapture#readme",
|
|
39
|
+
bugs: {
|
|
40
|
+
url: "https://github.com/phun-ky/wrapture/issues"
|
|
41
|
+
},
|
|
42
|
+
repository: {
|
|
43
|
+
type: "git",
|
|
44
|
+
url: "git+https://github.com/phun-ky/wrapture.git"
|
|
45
|
+
},
|
|
46
|
+
funding: "https://github.com/phun-ky/angle?sponsor=1",
|
|
47
|
+
license: "MIT",
|
|
48
|
+
author: "Alexander Vassbotn R\xF8yne-Helgesen <alexander@phun-ky.net>",
|
|
49
|
+
type: "module",
|
|
50
|
+
bin: {
|
|
51
|
+
wrapture: "./bin/wrapture.js"
|
|
52
|
+
},
|
|
53
|
+
scripts: {
|
|
54
|
+
build: "tsup",
|
|
55
|
+
commit: "npx git-cz",
|
|
56
|
+
"docs:gen": "node ./node_modules/.bin/typedoc",
|
|
57
|
+
release: "release-it",
|
|
58
|
+
start: "node ./bin/wrapture.js",
|
|
59
|
+
"style:code": "npx putout src",
|
|
60
|
+
"style:format": "./node_modules/.bin/eslint -c ./eslint.config.mjs src --fix && ./node_modules/.bin/prettier --write ./eslint.config.mjs src",
|
|
61
|
+
"style:lint": "./node_modules/.bin/eslint -c ./eslint.config.mjs src && ./node_modules/.bin/prettier --check src",
|
|
62
|
+
test: 'NODE_ENV=test glob -c "node --import tsx --test --no-warnings" "./src/**/__tests__/**/*.[jt]s"',
|
|
63
|
+
"pretest:ci": "rm -rf coverage && mkdir -p coverage",
|
|
64
|
+
"test:ci": 'NODE_ENV=test glob -c "node --import tsx --test --no-warnings --experimental-test-coverage --test-reporter=cobertura --test-reporter-destination=coverage/cobertura-coverage.xml --test-reporter=spec --test-reporter-destination=stdout" "./src/**/__tests__/**/*.[jt]s"'
|
|
65
|
+
},
|
|
66
|
+
dependencies: {
|
|
67
|
+
chalk: "^5.4.1",
|
|
68
|
+
commander: "^13.1.0",
|
|
69
|
+
ora: "^8.2.0"
|
|
70
|
+
},
|
|
71
|
+
devDependencies: {
|
|
72
|
+
"@release-it/conventional-changelog": "^10.0.0",
|
|
73
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
74
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
75
|
+
"@stylistic/eslint-plugin": "^4.2.0",
|
|
76
|
+
"@types/node": "^22.15.3",
|
|
77
|
+
cobertura: "^1.0.1",
|
|
78
|
+
eslint: "^9.20.0",
|
|
79
|
+
"eslint-config-phun-ky": "^1.0.0",
|
|
80
|
+
"git-cz": "^4.9.0",
|
|
81
|
+
"onnxruntime-web": "^1.22.0",
|
|
82
|
+
prettier: "^3.2.5",
|
|
83
|
+
putout: "^40.1.9",
|
|
84
|
+
"release-it": "^19.0.1",
|
|
85
|
+
"remark-github": "^12.0.0",
|
|
86
|
+
"remark-toc": "^9.0.0",
|
|
87
|
+
tslib: "^2.3.1",
|
|
88
|
+
tsup: "^8.4.0",
|
|
89
|
+
tsx: "^4.7.1",
|
|
90
|
+
typedoc: "^0.28.3",
|
|
91
|
+
"typedoc-plugin-frontmatter": "^1.0.0",
|
|
92
|
+
"typedoc-plugin-markdown": "^4.2.3",
|
|
93
|
+
"typedoc-plugin-mdn-links": "^5.0.1",
|
|
94
|
+
"typedoc-plugin-no-inherit": "^1.4.0",
|
|
95
|
+
"typedoc-plugin-remark": "^2.0.0",
|
|
96
|
+
"typedoc-plugin-rename-defaults": "^0.7.1",
|
|
97
|
+
typescript: "^5.0.0",
|
|
98
|
+
"unified-prettier": "^2.0.1"
|
|
99
|
+
},
|
|
100
|
+
engines: {
|
|
101
|
+
node: ">=22.0.0",
|
|
102
|
+
npm: ">=10.8.2"
|
|
103
|
+
},
|
|
104
|
+
publishConfig: {
|
|
105
|
+
access: "public"
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/utils/check-deps.ts
|
|
10
110
|
import chalk from "chalk";
|
|
11
|
-
import
|
|
111
|
+
import { spawnSync } from "node:child_process";
|
|
112
|
+
var printError = (title, body) => {
|
|
113
|
+
console.error(`
|
|
114
|
+
${chalk.red.bold("\u2718")} ${chalk.red.bold(title)}`);
|
|
115
|
+
console.error(chalk.white(body));
|
|
116
|
+
};
|
|
117
|
+
var checkPythonAvailable = () => {
|
|
118
|
+
const result = spawnSync("python3", ["--version"], { encoding: "utf-8" });
|
|
119
|
+
if (result.error || result.status !== 0) {
|
|
120
|
+
printError(
|
|
121
|
+
"Python 3 is not available.",
|
|
122
|
+
"Please install it from https://www.python.org/downloads/ and ensure it is added to your PATH."
|
|
123
|
+
);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var checkPythonDeps = () => {
|
|
128
|
+
const check = spawnSync(
|
|
129
|
+
"python3",
|
|
130
|
+
[
|
|
131
|
+
"-c",
|
|
132
|
+
`
|
|
133
|
+
import sys
|
|
134
|
+
missing = []
|
|
135
|
+
for module in ['torch', 'onnx', 'onnxsim', 'onnxruntime']:
|
|
136
|
+
try:
|
|
137
|
+
__import__(module)
|
|
138
|
+
except ImportError:
|
|
139
|
+
missing.append(module)
|
|
140
|
+
if missing:
|
|
141
|
+
print(', '.join(missing))
|
|
142
|
+
sys.exit(1)
|
|
143
|
+
`
|
|
144
|
+
],
|
|
145
|
+
{ encoding: "utf-8" }
|
|
146
|
+
);
|
|
147
|
+
if (check.status !== 0) {
|
|
148
|
+
const missing = check.stdout.trim().split(",").filter(Boolean);
|
|
149
|
+
printError(
|
|
150
|
+
"Missing Python dependencies.",
|
|
151
|
+
`Please install the following packages:
|
|
152
|
+
|
|
153
|
+
${chalk.yellow(
|
|
154
|
+
`python3 -m pip install ${missing.join(" ")}`
|
|
155
|
+
)}`
|
|
156
|
+
);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// src/utils/convert.ts
|
|
12
162
|
import { spawn } from "node:child_process";
|
|
13
163
|
import fs from "node:fs";
|
|
14
|
-
import path
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
var
|
|
164
|
+
import path from "node:path";
|
|
165
|
+
|
|
166
|
+
// src/utils/log-level.ts
|
|
167
|
+
var currentLevel = "info";
|
|
168
|
+
var levels = {
|
|
169
|
+
silent: 0,
|
|
170
|
+
error: 1,
|
|
171
|
+
warn: 2,
|
|
172
|
+
info: 3,
|
|
173
|
+
debug: 4
|
|
174
|
+
};
|
|
175
|
+
var setLogLevel = (level) => {
|
|
176
|
+
currentLevel = level;
|
|
177
|
+
};
|
|
178
|
+
var shouldLog = (level) => {
|
|
179
|
+
return levels[level] <= levels[currentLevel];
|
|
180
|
+
};
|
|
181
|
+
var log = {
|
|
182
|
+
debug: (...args) => shouldLog("debug") && console.debug("[debug]", ...args),
|
|
183
|
+
info: (...args) => shouldLog("info") && console.info("[info]", ...args),
|
|
184
|
+
warn: (...args) => shouldLog("warn") && console.warn("[warn]", ...args),
|
|
185
|
+
error: (...args) => shouldLog("error") && console.error("[error]", ...args)
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/utils/convert.ts
|
|
18
189
|
var convert = async (inputPath, outputDir, opts) => {
|
|
19
190
|
if (!fs.existsSync(inputPath)) {
|
|
20
191
|
throw new Error(`Input model file not found: ${inputPath}`);
|
|
21
192
|
}
|
|
22
|
-
|
|
193
|
+
log.info("Converting model to ONNX...");
|
|
23
194
|
return new Promise((resolve, reject) => {
|
|
24
|
-
const scriptPath = path.resolve(
|
|
195
|
+
const scriptPath = path.resolve(process.cwd(), "python/convert.py");
|
|
196
|
+
log.debug("Script path for `convert.py`:", scriptPath);
|
|
25
197
|
const args = [
|
|
26
198
|
scriptPath,
|
|
27
199
|
"--input",
|
|
@@ -33,17 +205,18 @@ var convert = async (inputPath, outputDir, opts) => {
|
|
|
33
205
|
];
|
|
34
206
|
if (opts.quantize) args.push("--quantize");
|
|
35
207
|
const python = spawn("python3", args);
|
|
36
|
-
python.stdout.on("data", (data) =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
208
|
+
python.stdout.on("data", (data) => {
|
|
209
|
+
log.debug("[python stdout]", data.toString());
|
|
210
|
+
});
|
|
211
|
+
python.stderr.on("data", (data) => {
|
|
212
|
+
log.error("[python stderr]", data.toString());
|
|
213
|
+
});
|
|
41
214
|
python.on("close", (code) => {
|
|
42
215
|
if (code === 0) {
|
|
43
|
-
|
|
216
|
+
log.info("Model converted successfully");
|
|
44
217
|
resolve();
|
|
45
218
|
} else {
|
|
46
|
-
|
|
219
|
+
log.error("Model conversion failed");
|
|
47
220
|
reject(new Error(`convert.py exited with code ${code}`));
|
|
48
221
|
}
|
|
49
222
|
});
|
|
@@ -51,11 +224,10 @@ var convert = async (inputPath, outputDir, opts) => {
|
|
|
51
224
|
};
|
|
52
225
|
|
|
53
226
|
// src/utils/generate-wrapper.ts
|
|
54
|
-
import ora2 from "ora";
|
|
55
227
|
import fs2 from "node:fs";
|
|
56
228
|
import path2 from "node:path";
|
|
57
229
|
var generateWrapper = async (outputDir, opts) => {
|
|
58
|
-
|
|
230
|
+
log.info("Generating wrapper files...");
|
|
59
231
|
const wrapper = `import { InferenceSession, Tensor } from 'onnxruntime-web';
|
|
60
232
|
|
|
61
233
|
const softmax = (logits) => {
|
|
@@ -112,36 +284,55 @@ export function loadModel(): Promise<LoadedModel>;`;
|
|
|
112
284
|
try {
|
|
113
285
|
fs2.writeFileSync(path2.join(outputDir, "wrapped.ts"), wrapper);
|
|
114
286
|
fs2.writeFileSync(path2.join(outputDir, "wrapped.d.ts"), typings);
|
|
115
|
-
|
|
287
|
+
log.info("Wrapper files generated");
|
|
116
288
|
} catch (error) {
|
|
117
|
-
|
|
289
|
+
log.error("Failed generate wrapper files");
|
|
118
290
|
throw error;
|
|
119
291
|
}
|
|
120
292
|
};
|
|
121
293
|
|
|
122
294
|
// src/wrapture.ts
|
|
123
295
|
var program = new Command();
|
|
124
|
-
program.name("wrapture").description(
|
|
296
|
+
program.name("wrapture").description(
|
|
297
|
+
`\u{1F300} ${chalk2.blue("One-click model exporter: ")}from PyTorch to Web-ready JS/TS.
|
|
298
|
+
|
|
299
|
+
Wrapture lets you go from a Python-trained model to deployable JavaScript with a single command.
|
|
300
|
+
It generates TypeScript bindings and a Web/Node-compatible wrapper, using WebGPU/WASM-ready ONNX runtimes.
|
|
301
|
+
|
|
302
|
+
Report issues here: https://github.com/phun-ky/wrapture`
|
|
303
|
+
).version(package_default.version).requiredOption("-i, --input <file>", "path to the PyTorch model (.pt)").requiredOption(
|
|
125
304
|
"-o, --output <dir>",
|
|
126
|
-
"
|
|
127
|
-
).option("--quantize", "
|
|
305
|
+
"output directory for the wrapped model"
|
|
306
|
+
).option("--quantize", "apply quantization to reduce model size").option("--format <type>", "export format: onnx (default)", "onnx").option(
|
|
128
307
|
"--backend <backend>",
|
|
129
|
-
"
|
|
308
|
+
"inference backend: webgpu | wasm | cpu",
|
|
130
309
|
"webgpu"
|
|
310
|
+
).option(
|
|
311
|
+
"--logLevel <level>",
|
|
312
|
+
"set log level: silent | error | warn | info | debug",
|
|
313
|
+
"error"
|
|
131
314
|
).action(async (opts) => {
|
|
315
|
+
checkPythonAvailable();
|
|
316
|
+
checkPythonDeps();
|
|
132
317
|
const input = path3.resolve(opts.input);
|
|
133
318
|
const output = path3.resolve(opts.output);
|
|
319
|
+
setLogLevel(
|
|
320
|
+
process.env.LOGLEVEL || opts.logLevel || "error"
|
|
321
|
+
);
|
|
134
322
|
if (!existsSync(input)) {
|
|
135
|
-
console.error(
|
|
323
|
+
console.error(
|
|
324
|
+
`${chalk2.red.bold("\u2718 Input file not found:")} ${chalk2.white(input)}`
|
|
325
|
+
);
|
|
136
326
|
process.exit(1);
|
|
137
327
|
}
|
|
138
|
-
|
|
328
|
+
const spinner = ora("Wrapture: Exporting model...").start();
|
|
139
329
|
try {
|
|
140
330
|
await convert(input, output, opts);
|
|
141
331
|
await generateWrapper(output, opts);
|
|
142
|
-
|
|
332
|
+
spinner.succeed("Done! Your model is wrapped and ready.");
|
|
143
333
|
} catch (err) {
|
|
144
|
-
|
|
334
|
+
spinner.fail("Failed to export model:");
|
|
335
|
+
console.error(err);
|
|
145
336
|
process.exit(1);
|
|
146
337
|
}
|
|
147
338
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrapture",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Wrapture lets you go from a Python-trained model to deployable JavaScript with a single command. It generates TypeScript bindings and a Web/Node-compatible wrapper, using WebGPU/WASM-ready ONNX runtimes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"onnx",
|
package/python/convert.py
CHANGED
|
@@ -43,9 +43,9 @@ def convert_to_onnx(input_path, output_path, quantize=False):
|
|
|
43
43
|
assert check, "Simplified model could not be validated"
|
|
44
44
|
onnx.checker.check_model(model_simp) # throw if broken
|
|
45
45
|
onnx.save(model_simp, output_model_path)
|
|
46
|
-
print("
|
|
46
|
+
print("β ONNX model simplified.")
|
|
47
47
|
|
|
48
|
-
print(f"
|
|
48
|
+
print(f"β Exported ONNX model to: {output_model_path}")
|
|
49
49
|
|
|
50
50
|
if quantize:
|
|
51
51
|
quant_model_path = os.path.join(output_path, 'model_quant.onnx')
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* global process */
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
const printError = (title: string, body: string) => {
|
|
7
|
+
console.error(`\n${chalk.red.bold('β')} ${chalk.red.bold(title)}`);
|
|
8
|
+
console.error(chalk.white(body));
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const checkPythonAvailable = (): void => {
|
|
12
|
+
const result = spawnSync('python3', ['--version'], { encoding: 'utf-8' });
|
|
13
|
+
|
|
14
|
+
if (result.error || result.status !== 0) {
|
|
15
|
+
printError(
|
|
16
|
+
'Python 3 is not available.',
|
|
17
|
+
'Please install it from https://www.python.org/downloads/ and ensure it is added to your PATH.'
|
|
18
|
+
);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const checkPythonDeps = (): void => {
|
|
24
|
+
const check = spawnSync(
|
|
25
|
+
'python3',
|
|
26
|
+
[
|
|
27
|
+
'-c',
|
|
28
|
+
`
|
|
29
|
+
import sys
|
|
30
|
+
missing = []
|
|
31
|
+
for module in ['torch', 'onnx', 'onnxsim', 'onnxruntime']:
|
|
32
|
+
try:
|
|
33
|
+
__import__(module)
|
|
34
|
+
except ImportError:
|
|
35
|
+
missing.append(module)
|
|
36
|
+
if missing:
|
|
37
|
+
print(', '.join(missing))
|
|
38
|
+
sys.exit(1)
|
|
39
|
+
`
|
|
40
|
+
],
|
|
41
|
+
{ encoding: 'utf-8' }
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (check.status !== 0) {
|
|
45
|
+
const missing = check.stdout.trim().split(',').filter(Boolean);
|
|
46
|
+
|
|
47
|
+
printError(
|
|
48
|
+
'Missing Python dependencies.',
|
|
49
|
+
`Please install the following packages:\n\n ${chalk.yellow(
|
|
50
|
+
`python3 -m pip install ${missing.join(' ')}`
|
|
51
|
+
)}`
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
};
|
package/src/utils/convert.ts
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
/* eslint-disable import/no-unused-modules */
|
|
2
2
|
/* global process */
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import ora from 'ora';
|
|
5
|
-
|
|
6
3
|
import { spawn } from 'node:child_process';
|
|
7
4
|
import fs from 'node:fs';
|
|
8
|
-
import path
|
|
9
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
const __dirname = dirname(__filename);
|
|
7
|
+
import { log } from './log-level.js';
|
|
13
8
|
|
|
14
9
|
/**
|
|
15
10
|
* Options for the {@link convert} function.
|
|
@@ -60,10 +55,13 @@ export const convert = async (
|
|
|
60
55
|
throw new Error(`Input model file not found: ${inputPath}`);
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
|
|
58
|
+
log.info('Converting model to ONNX...');
|
|
64
59
|
|
|
65
60
|
return new Promise((resolve, reject) => {
|
|
66
|
-
const scriptPath = path.resolve(
|
|
61
|
+
const scriptPath = path.resolve(process.cwd(), 'python/convert.py');
|
|
62
|
+
|
|
63
|
+
log.debug('Script path for `convert.py`:', scriptPath);
|
|
64
|
+
|
|
67
65
|
const args = [
|
|
68
66
|
scriptPath,
|
|
69
67
|
'--input',
|
|
@@ -78,18 +76,21 @@ export const convert = async (
|
|
|
78
76
|
|
|
79
77
|
const python = spawn('python3', args);
|
|
80
78
|
|
|
81
|
-
python.stdout.on('data', (data) =>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
python.stdout.on('data', (data) => {
|
|
80
|
+
log.debug('[python stdout]', data.toString());
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
python.stderr.on('data', (data) => {
|
|
84
|
+
log.error('[python stderr]', data.toString());
|
|
85
|
+
});
|
|
85
86
|
|
|
86
87
|
python.on('close', (code) => {
|
|
87
88
|
if (code === 0) {
|
|
88
|
-
|
|
89
|
+
log.info('Model converted successfully');
|
|
89
90
|
|
|
90
91
|
resolve();
|
|
91
92
|
} else {
|
|
92
|
-
|
|
93
|
+
log.error('Model conversion failed');
|
|
93
94
|
|
|
94
95
|
reject(new Error(`convert.py exited with code ${code}`));
|
|
95
96
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/* eslint-disable import/no-unused-modules */
|
|
3
2
|
import fs from 'node:fs';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
|
|
5
|
+
import { log } from './log-level.js';
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* Options for generating ONNX wrapper files.
|
|
8
9
|
*/
|
|
@@ -38,10 +39,11 @@ export interface GenerateWrapperOptionsInterface {
|
|
|
38
39
|
*/
|
|
39
40
|
export const generateWrapper = async (
|
|
40
41
|
outputDir: string,
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
opts: GenerateWrapperOptionsInterface
|
|
43
44
|
): Promise<void> => {
|
|
44
|
-
|
|
45
|
+
log.info('Generating wrapper files...');
|
|
46
|
+
|
|
45
47
|
const wrapper = `import { InferenceSession, Tensor } from 'onnxruntime-web';
|
|
46
48
|
|
|
47
49
|
const softmax = (logits) => {
|
|
@@ -99,9 +101,10 @@ export function loadModel(): Promise<LoadedModel>;`;
|
|
|
99
101
|
try {
|
|
100
102
|
fs.writeFileSync(path.join(outputDir, 'wrapped.ts'), wrapper);
|
|
101
103
|
fs.writeFileSync(path.join(outputDir, 'wrapped.d.ts'), typings);
|
|
102
|
-
|
|
104
|
+
|
|
105
|
+
log.info('Wrapper files generated');
|
|
103
106
|
} catch (error) {
|
|
104
|
-
|
|
107
|
+
log.error('Failed generate wrapper files');
|
|
105
108
|
throw error;
|
|
106
109
|
}
|
|
107
110
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
export type LogLevelType = 'silent' | 'error' | 'warn' | 'info' | 'debug';
|
|
3
|
+
|
|
4
|
+
let currentLevel: LogLevelType = 'info';
|
|
5
|
+
|
|
6
|
+
const levels: Record<LogLevelType, number> = {
|
|
7
|
+
silent: 0,
|
|
8
|
+
error: 1,
|
|
9
|
+
warn: 2,
|
|
10
|
+
info: 3,
|
|
11
|
+
debug: 4
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const setLogLevel = (level: LogLevelType) => {
|
|
15
|
+
currentLevel = level;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const shouldLog = (level: LogLevelType): boolean => {
|
|
19
|
+
return levels[level] <= levels[currentLevel];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const log = {
|
|
23
|
+
debug: (...args: unknown[]) =>
|
|
24
|
+
shouldLog('debug') && console.debug('[debug]', ...args),
|
|
25
|
+
info: (...args: unknown[]) =>
|
|
26
|
+
shouldLog('info') && console.info('[info]', ...args),
|
|
27
|
+
warn: (...args: unknown[]) =>
|
|
28
|
+
shouldLog('warn') && console.warn('[warn]', ...args),
|
|
29
|
+
error: (...args: unknown[]) =>
|
|
30
|
+
shouldLog('error') && console.error('[error]', ...args)
|
|
31
|
+
};
|
package/src/wrapture.ts
CHANGED
|
@@ -2,48 +2,76 @@
|
|
|
2
2
|
/* global process */
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
|
+
import ora from 'ora';
|
|
5
6
|
|
|
6
7
|
import { existsSync } from 'node:fs';
|
|
7
8
|
import path from 'node:path';
|
|
8
9
|
|
|
10
|
+
import pkg from '../package.json';
|
|
11
|
+
|
|
12
|
+
import { checkPythonAvailable, checkPythonDeps } from './utils/check-deps.js';
|
|
9
13
|
import { convert } from './utils/convert.js';
|
|
10
14
|
import { generateWrapper } from './utils/generate-wrapper.js';
|
|
15
|
+
import { LogLevelType, setLogLevel } from './utils/log-level.js';
|
|
11
16
|
|
|
12
17
|
const program = new Command();
|
|
13
18
|
|
|
14
19
|
program
|
|
15
20
|
.name('wrapture')
|
|
16
|
-
.description(
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
.description(
|
|
22
|
+
`π ${chalk.blue('One-click model exporter: ')}from PyTorch to Web-ready JS/TS.
|
|
23
|
+
|
|
24
|
+
Wrapture lets you go from a Python-trained model to deployable JavaScript with a single command.
|
|
25
|
+
It generates TypeScript bindings and a Web/Node-compatible wrapper, using WebGPU/WASM-ready ONNX runtimes.
|
|
26
|
+
|
|
27
|
+
Report issues here: https://github.com/phun-ky/wrapture`
|
|
28
|
+
)
|
|
29
|
+
.version(pkg.version)
|
|
30
|
+
.requiredOption('-i, --input <file>', 'path to the PyTorch model (.pt)')
|
|
19
31
|
.requiredOption(
|
|
20
32
|
'-o, --output <dir>',
|
|
21
|
-
'
|
|
33
|
+
'output directory for the wrapped model'
|
|
22
34
|
)
|
|
23
|
-
.option('--quantize', '
|
|
24
|
-
.option('--format <type>', '
|
|
35
|
+
.option('--quantize', 'apply quantization to reduce model size')
|
|
36
|
+
.option('--format <type>', 'export format: onnx (default)', 'onnx')
|
|
25
37
|
.option(
|
|
26
38
|
'--backend <backend>',
|
|
27
|
-
'
|
|
39
|
+
'inference backend: webgpu | wasm | cpu',
|
|
28
40
|
'webgpu'
|
|
29
41
|
)
|
|
42
|
+
.option(
|
|
43
|
+
'--logLevel <level>',
|
|
44
|
+
'set log level: silent | error | warn | info | debug',
|
|
45
|
+
'error'
|
|
46
|
+
)
|
|
30
47
|
.action(async (opts) => {
|
|
48
|
+
checkPythonAvailable();
|
|
49
|
+
checkPythonDeps();
|
|
50
|
+
|
|
31
51
|
const input = path.resolve(opts.input);
|
|
32
52
|
const output = path.resolve(opts.output);
|
|
33
53
|
|
|
54
|
+
setLogLevel(
|
|
55
|
+
(process.env.LOGLEVEL as LogLevelType) || opts.logLevel || 'error'
|
|
56
|
+
);
|
|
57
|
+
|
|
34
58
|
if (!existsSync(input)) {
|
|
35
|
-
console.error(
|
|
59
|
+
console.error(
|
|
60
|
+
`${chalk.red.bold('β Input file not found:')} ${chalk.white(input)}`
|
|
61
|
+
);
|
|
36
62
|
process.exit(1);
|
|
37
63
|
}
|
|
38
64
|
|
|
39
|
-
|
|
65
|
+
const spinner = ora('Wrapture: Exporting model...').start();
|
|
40
66
|
|
|
41
67
|
try {
|
|
42
68
|
await convert(input, output, opts);
|
|
43
69
|
await generateWrapper(output, opts);
|
|
44
|
-
|
|
70
|
+
spinner.succeed('Done! Your model is wrapped and ready.');
|
|
45
71
|
} catch (err) {
|
|
46
|
-
|
|
72
|
+
spinner.fail('Failed to export model:');
|
|
73
|
+
console.error(err);
|
|
74
|
+
|
|
47
75
|
process.exit(1);
|
|
48
76
|
}
|
|
49
77
|
});
|