@jseeio/jsee 0.2.1 → 0.2.5

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.
@@ -0,0 +1 @@
1
+ (()=>{var __webpack_modules__={555:()=>{eval("function getModelFuncJS(schema, target, log=console.log) {\n switch (schema.model.type) {\n case 'class':\n log('Init class')\n const modelClass = new target()\n return (...a) => {\n return modelClass[this.schema.model.method || 'predict'](...a)\n }\n case 'async-init':\n log('Function with async init')\n return target().then((m) => {\n log('Async init resolved: ', m)\n this.modelFunc = m\n })\n default:\n log('Init function')\n return target\n }\n}\n\n\n//# sourceURL=webpack://@jseeio/jsee/./src/utils.js?")},736:(__unused_webpack_module,__unused_webpack___webpack_exports__,__webpack_require__)=>{"use strict";eval("/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(555);\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_utils_js__WEBPACK_IMPORTED_MODULE_0__);\n\n\nconsole.log('!!!', _utils_js__WEBPACK_IMPORTED_MODULE_0__.getModelFuncJS)\n\nfunction log () {\n const args = Array.prototype.slice.call(arguments);\n args.unshift('[Worker]')\n console.log(args)\n postMessage({_status: 'log', _log: args})\n}\n\nfunction initTF (model) {\n throw new Error('Tensorflow in worker (not implemented)')\n}\n\nfunction initPython (model) {\n throw new Error('Python in worker (not implemented)')\n}\n\nfunction initJS (model) {\n this.container = model.container\n\n if (model.code) {\n log('Load code as a string')\n // https://github.com/altbdoor/blob-worker/blob/master/blobWorker.js\n importScripts(URL.createObjectURL(new Blob([model.code], { type: 'text/javascript' })))\n } else if (model.url) {\n log('Load script from URL:', model.url)\n importScripts(model.url)\n } else {\n log('No script provided')\n }\n\n this.modelFunc = (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.getModelFuncJS)(model, this[model.name], log)\n console.log('>>>', this.modelFunc)\n postMessage({_status: 'loaded'})\n}\n\nonmessage = function (e) {\n\n var data = e.data\n log('Received message of type:', typeof data)\n\n if ((typeof data === 'object') && ((data.url) || (data.code))) {\n /*\n INIT MESSAGE\n */\n let model = data\n log('Init...')\n\n switch (model.type) {\n case 'tf':\n initTF(model)\n break\n case 'py':\n initPython(model)\n break\n case 'function':\n case 'class':\n case 'async-init':\n case 'async-function':\n initJS.call(this, model)\n break\n }\n } else {\n /*\n :w\n CALL MESSAGE\n */\n var res\n if (typeof this.modelFunc === 'string') {\n // Python model:\n log('Calling Python model')\n /*\n const keys = Object.keys(data)\n for (let key of keys) {\n self[key] = data[key];\n }\n self.pyodide.runPythonAsync(this.model, () => {})\n .then((res) => {\n console.log('[Worker] Py results: ', typeof res, res)\n\t postMessage(res)\n })\n .catch((err) => {\n // self.postMessage({error : err.message});\n })\n */\n } else {\n // JavaScript model\n log('Calling JavaScript model')\n if (this.container === 'args') {\n log('Applying inputs as arguments')\n res = this.modelFunc.apply(null, data)\n } else {\n // JS object or array\n log('Applying inputs as object/array')\n res = this.modelFunc(data, log)\n }\n // Return promise value or just regular value\n // Promise.resolve handles both cases\n Promise.resolve(res).then(r => { postMessage(r) })\n }\n }\n}\n\n\n//# sourceURL=webpack://@jseeio/jsee/./src/worker.js?")}},__webpack_module_cache__={};function __webpack_require__(e){var n=__webpack_module_cache__[e];if(void 0!==n)return n.exports;var o=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](o,o.exports,__webpack_require__),o.exports}__webpack_require__.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(n,{a:n}),n},__webpack_require__.d=(e,n)=>{for(var o in n)__webpack_require__.o(n,o)&&!__webpack_require__.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},__webpack_require__.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n);var __webpack_exports__=__webpack_require__(736)})();
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ launch: {
3
+ dumpio: false, // dump browser errors to jest
4
+ headless: process.env.HEADLESS !== 'false',
5
+ product: 'chrome',
6
+ },
7
+ // server: {
8
+ // command: 'http-server',
9
+ // port: 8081,
10
+ // },
11
+ browserContext: 'default',
12
+ }
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ preset: 'jest-puppeteer',
3
+ verbose: true,
4
+ }
5
+
6
+ module.exports = config
7
+
package/load.html CHANGED
@@ -13,11 +13,15 @@
13
13
  <script src="dist/jsee.js" type="text/javascript"></script>
14
14
  <script>
15
15
  var params = new URLSearchParams(window.location.search)
16
- var schema = params.get('s')
17
- if (schema) {
18
- if (typeof schema === 'string') {
19
- schema = schema.includes('/') ? schema : '/apps/' + schema + '/schema.json'
16
+ var schemaStr = params.get('s')
17
+ if (schemaStr) {
18
+ let schema
19
+ try {
20
+ schema = JSON.parse(schemaStr);
21
+ } catch (e) {
22
+ schema = schemaStr.includes('/') ? schemaStr : '/apps/' + schemaStr + '/schema.json'
20
23
  }
24
+ console.log('[Loader] Schema:', schemaStr, schema)
21
25
  const env = new JSEE({
22
26
  container: document.getElementById('jsee-container'),
23
27
  schema: schema
package/main.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createVueApp } from './src/app'
2
2
  import Worker from './src/worker.js'
3
3
 
4
+ const utils = require('./src/utils')
5
+
4
6
  const { Notyf } = require('notyf')
5
7
  const notyf = new Notyf({
6
8
  types: [
@@ -25,8 +27,11 @@ require('notyf/notyf.min.css')
25
27
  const fetch = window['fetch']
26
28
  const Blob = window['Blob']
27
29
 
30
+ let verbose = true
28
31
  function log () {
29
- console.log(`[JSEE v${VERSION}]`, ...arguments)
32
+ if (verbose) {
33
+ console.log(`[JSEE v${VERSION}]`, ...arguments)
34
+ }
30
35
  }
31
36
 
32
37
  // const Worker = window['Worker']
@@ -42,6 +47,12 @@ function isObject (item) {
42
47
  return (typeof item === 'object' && !Array.isArray(item) && item !== null)
43
48
  }
44
49
 
50
+ function getName (code) {
51
+ const words = code.split(' ')
52
+ const functionIndex = words.findIndex((word) => word == 'function')
53
+ return words[numberIndex + 1]
54
+ }
55
+
45
56
  // Return input value
46
57
  function getValue (input) {
47
58
  if (input.type === 'group') {
@@ -55,14 +66,60 @@ function getValue (input) {
55
66
  }
56
67
  }
57
68
 
69
+ function getType (model) {
70
+ if (model.code && typeof model.code === 'string' && model.code.split(' ').map(v => v.trim()).includes('def')) {
71
+ return 'py'
72
+ } else if (model.url) {
73
+ return 'post'
74
+ }
75
+ return 'function'
76
+ }
77
+
78
+ // Nice trick to get a function parameters by Jack Allan
79
+ // From: https://stackoverflow.com/a/9924463/2998960
80
+ const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg
81
+ const ARGUMENT_NAMES = /([^\s,]+)/g
82
+ function getParamNames (func) {
83
+ const fnStr = func.toString().replace(STRIP_COMMENTS, '')
84
+ let result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES)
85
+ if (result === null)
86
+ result = []
87
+ return result
88
+ }
89
+
90
+ function getInputs (model) {
91
+ if (model.code) {
92
+ const params = getParamNames(model.code)
93
+ return params.map(p => ({
94
+ 'name': p,
95
+ 'type': 'string'
96
+ }))
97
+ }
98
+ return []
99
+ }
100
+
101
+ function getFunctionContainer (target) {
102
+ // Check if the number of parameters is > 1, then 'args'
103
+ }
104
+
58
105
  export default class JSEE {
59
- constructor (params) {
106
+ constructor (params, alt) {
107
+ // Check if JSEE was initialized with 2 args rather than 1 obj
108
+ if (('model' in params) || !(typeof alt === 'undefined')) {
109
+ params = {
110
+ 'schema': params,
111
+ 'container': alt
112
+ }
113
+ }
114
+
115
+ verbose = !(params.verbose === false)
116
+
60
117
  log('Initializing JSEE with parameters: ', params)
61
118
  params.schema = params.schema || params.config
62
119
  this.params = params
63
120
  this.__version__ = VERSION
64
121
 
65
- // Get schema then initialize a model
122
+ // Get schema then initialize a new environment
66
123
  if (params.schema) {
67
124
  if (typeof params.schema === 'object') {
68
125
  log('Received schema as object')
@@ -87,186 +144,143 @@ export default class JSEE {
87
144
  notyf.success(txt)
88
145
  }
89
146
 
90
- // Initialize model from schema
91
147
  init (schema) {
92
- log('Initializing schema', schema)
148
+ this.loadCode(schema).then((code) => { // -> code
149
+ this.initSchema(schema, code) // -> this.schema
150
+ this.initVue() // -> this.app, this.data
151
+ this.initWorker() // -> this.worker
152
+ this.initRender() // -> this.renderFunc
153
+ this.initModel() // -> this.modelFunc (depends on this.worker)
154
+ })
155
+ }
93
156
 
94
- // Convert JS code to string
95
- if (schema.model.code && (typeof schema.model.code !== 'string')) {
96
- log('Convert code in schema to string')
97
- schema.model.code = schema.model.code.toString()
98
- }
157
+ loadCode (schema) {
158
+ const initPromise = new Promise((resolve, reject) => {
159
+ // Unwind this ball of possible cases
160
+ let url = schema.model.url
161
+ if (url && (url.includes('.js') || url.includes('.py'))) {
162
+ // Update model URL if needed
163
+ if (!url.includes('/') && this.schemaUrl && this.schemaUrl.includes('/')) {
164
+ url = window.location.protocol + '//' + window.location.host + this.schemaUrl.split('/').slice(0, -1).join('/') + '/' + url
165
+ log(`Changed the old model URL to ${url} (based on the schema URL)`)
166
+ }
167
+ fetch(url)
168
+ .then(res => res.text())
169
+ .then(res => {
170
+ log('Loaded code from:', url)
171
+ resolve(res)
172
+ })
173
+ } else if (typeof schema === 'function') {
174
+ log('Code is: schema')
175
+ resolve(schema)
176
+ } else if (typeof schema.model === 'function') {
177
+ log('Code is: schema.model')
178
+ resolve(schema.model)
179
+ } else if (!(typeof schema.model.code === 'undefined')) {
180
+ log('Code is: schema.model.code')
181
+ resolve(schema.model.code)
182
+ } else {
183
+ log('No code. Probably API...')
184
+ resolve(undefined)
185
+ }
186
+ })
187
+
188
+ return initPromise
189
+ }
190
+
191
+ initSchema (schema, code) {
192
+ log('Initializing schema')
99
193
 
100
- // Update model URL if needed
101
- if (schema.model.url && !schema.model.url.includes('/') && this.schemaUrl && this.schemaUrl.includes('/')) {
102
- let oldModelUrl = schema.model.url
103
- log('Schema URL:', this.schemaUrl)
104
- schema.model.url = window.location.protocol + '//' + window.location.host + this.schemaUrl.split('/').slice(0, -1).join('/') + '/' + oldModelUrl
105
- log('Changed the old model URL to absolute one:', oldModelUrl, schema.model.url)
194
+ // Check for empty model block
195
+ if (typeof schema.model === 'undefined') {
196
+ schema.model = {}
106
197
  }
107
198
 
199
+ schema.model.code = code
200
+
201
+ // Check for super minimal config
108
202
  // Check for worker flag
109
203
  if (typeof schema.model.worker === 'undefined') {
110
204
  schema.model.worker = true
111
205
  }
112
206
 
113
- // Check if name is present, if not - get name from the file
114
- if (typeof schema.model.name === 'undefined') {
115
- // Two options here
116
- if (schema.model.url) {
117
- // 1. Get the name from the file name
118
- schema.model.name = schema.model.url.split('/').pop().split('.')[0]
119
- log('Use name from url: ', schema.model.name)
120
- } else if (schema.model.code) {
121
- // 2. Get the name from the url
122
- schema.model.name = schema.model.code.name
123
- log('Use name from code: ', schema.model.name)
207
+ // Check inputs
208
+ // Relies on model.code
209
+ // So run after possible fetching
210
+ if (typeof schema.inputs === 'undefined') {
211
+ schema.model.container = 'args'
212
+ schema.inputs = getInputs(schema.model)
213
+ }
214
+
215
+ // Relies on input check
216
+ // Set default input type
217
+ schema.inputs.forEach(input => {
218
+ if (typeof input.type === 'undefined') {
219
+ input.type = 'string'
124
220
  }
221
+ })
222
+
223
+ // Infer model type
224
+ if (typeof schema.model.type === 'undefined') {
225
+ schema.model.type = getType(schema.model)
226
+ }
227
+
228
+ // Update model name if absent
229
+ if ((typeof schema.model.name === 'undefined') && (schema.model.url) && (schema.model.url.includes('.js'))) {
230
+ schema.model.name = schema.model.url.split('/').pop().split('.')[0]
231
+ log('Use model name from url: ', schema.model.name)
125
232
  }
126
233
 
234
+ // At this point we have all code in model.code or api
127
235
  this.schema = clone(schema)
236
+ }
128
237
 
129
- // Init Vue app
130
- this.app = createVueApp(this, this.schema, (container) => {
238
+ initVue () {
239
+ log('Initializing VUE')
240
+ this.app = createVueApp(this, (container) => {
131
241
  // Called when the app is mounted
132
242
  // FYI "this" here refers to port object
133
243
  this.outputsContainer = container.querySelector('#outputs')
134
244
  this.inputsContainer = container.querySelector('#inputs')
135
245
  this.modelContainer = container.querySelector('#model')
136
-
137
246
  // Init overlay
138
- this.overlay = new Overlay(this.inputsContainer)
139
- })
247
+ this.overlay = new Overlay(this.inputsContainer ? this.inputsContainer : this.outputsContainer)
248
+ }, log)
140
249
  this.data = this.app.$data
250
+ }
141
251
 
142
- // Init Model
143
- // ----------
144
- if (this.schema.model.type === 'py') {
145
- // Add loading indicator
146
- this.overlay.show()
147
- let script = document.createElement('script')
148
- script.src = 'https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js'
149
- script.onload = async () => {
150
- this.pyodide = await loadPyodide({ indexURL : "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/" });
151
- notyf.success('Loaded: Python')
152
- const resRaw = await fetch(this.schema.model.url)
153
- const res = await resRaw.text()
154
- this.pymodel = res
155
- log('Loaded python code:', res)
156
- // Check if micropip is used
157
- if (res.includes('micropip')) {
158
- await this.pyodide.loadPackage('micropip')
159
- log('Loaded micropip')
160
- }
161
- // Import packages if defined
162
- if ('packages' in this.schema.model) {
163
- await this.pyodide.loadPackage(this.schema.model.packages)
164
- log('Loaded packages from schema')
165
- } else {
166
- await this.pyodide.loadPackagesFromImports(res)
167
- log('Loaded packages from Python code')
168
- }
252
+ initWorker () {
253
+ if (this.schema.model.worker) {
254
+ log('Initializing Worker')
255
+ this.worker = new Worker()
256
+ this.worker.onmessage = (e) => {
169
257
  this.overlay.hide()
170
- }
171
- document.head.appendChild(script)
172
- } else if (['function', 'class', 'async-init', 'async-function'].includes(this.schema.model.type)) {
173
- // Initialize worker with the model
174
- if (this.schema.model.worker) {
175
- // this.worker = new Worker(new URL('./src/worker.js', import.meta.url))
176
- this.worker = new Worker()
177
- if (this.schema.model.url) {
178
- fetch(this.schema.model.url)
179
- .then(res => res.text())
180
- .then(res => {
181
- log('Loaded js code for worker')
182
- this.schema.model.code = res
183
- this.worker.postMessage(this.schema.model)
184
- })
185
- } else if (typeof this.schema.model.code !== 'undefined') {
186
- this.worker.postMessage(this.schema.model)
187
- } else {
188
- notyf.error('No code provided')
189
- }
190
-
191
- this.worker.onmessage = (e) => {
192
- this.overlay.hide()
193
- const res = e.data
194
- if ((typeof res === 'object') && (res._status)) {
195
- switch (res._status) {
196
- case 'loaded':
197
- notyf.success('Loaded: JS model (in worker)')
198
- break
199
- case 'log':
200
- log(...res._log)
201
- break
202
- }
203
- } else {
204
- log('Response from worker:', res)
205
- this.output(res)
206
- }
207
- }
208
- this.worker.onerror = (e) => {
209
- this.overlay.hide()
210
- notyf.error(e.message)
211
- log('Error from worker:', e)
212
- }
213
- } else {
214
- // Initialize model in main window
215
- log('Init model in window')
216
- let script = document.createElement('script')
217
- script.src = this.schema.model.url
218
- script.onload = () => {
219
- notyf.success('Loaded: JS model')
220
- this.overlay.hide()
221
- log('Loaded JS model in main window')
222
-
223
- // Initializing the model (same in worker)
224
- if (this.schema.model.type === 'class') {
225
- log('Init class')
226
- const modelClass = new window[this.schema.model.name]()
227
- this.modelFunc = (...a) => {
228
- return modelClass[this.schema.model.method || 'predict'](...a)
229
- }
230
- } else if (this.schema.model.type === 'async-init') {
231
- log('Init function with promise')
232
- window[this.schema.model.name]().then((m) => {
233
- log('Async init resolved: ', m)
234
- this.modelFunc = m
235
- })
236
- } else {
237
- log('Init function')
238
- this.modelFunc = window[this.schema.model.name]
258
+ const res = e.data
259
+ if ((typeof res === 'object') && (res._status)) {
260
+ switch (res._status) {
261
+ case 'loaded':
262
+ notyf.success('Loaded: JS model (in worker)')
263
+ break
264
+ case 'log':
265
+ log(...res._log)
266
+ break
239
267
  }
268
+ } else {
269
+ log('Response from worker:', res)
270
+ this.output(res)
240
271
  }
241
- document.head.appendChild(script)
242
272
  }
243
- } else if (this.schema.model.type === 'tf') {
244
- // Initialize TF
245
- let script = document.createElement('script')
246
- script.src = 'dist/tf.min.js'
247
- script.onload = () => {
248
- log('Loaded TF.js')
273
+ this.worker.onerror = (e) => {
249
274
  this.overlay.hide()
250
- window['tf'].loadLayersModel(this.schema.model.url).then(res => {
251
- log('Loaded Tensorflow model')
252
- })
253
- }
254
- document.head.appendChild(script)
255
- } else if (this.schema.model.type === 'get') {
256
- this.overlay.hide()
257
- this.modelFunc = (data) => {
258
- const query = new window['URLSearchParams'](data).toString()
259
- log('Generated query string:', query)
260
- const resPromise = fetch(this.schema.model.url +'?' + query)
261
- .then(response => response.json())
262
- return resPromise
275
+ notyf.error(e.message)
276
+ log('Error from worker:', e)
263
277
  }
264
278
  }
279
+ }
265
280
 
266
- // Init render
267
- // -----------
281
+ initRender () {
268
282
  if (this.schema.render && this.schema.render.url) {
269
- log('Init render in window')
283
+ log('Initializing a render function')
270
284
  let script = document.createElement('script')
271
285
  script.src = this.schema.render.url
272
286
  script.onload = () => {
@@ -295,6 +309,130 @@ export default class JSEE {
295
309
  }
296
310
  }
297
311
 
312
+ initModel () {
313
+ log('Initializing a model function')
314
+ switch (this.schema.model.type) {
315
+ case 'py':
316
+ this.initPython()
317
+ break
318
+ case 'tf':
319
+ this.initTF()
320
+ break
321
+ case 'function':
322
+ case 'class':
323
+ case 'async-init':
324
+ case 'async-function':
325
+ this.initJS()
326
+ break
327
+ case 'get':
328
+ case 'post':
329
+ this.initAPI()
330
+ break
331
+ default:
332
+ notyf.error('No type information')
333
+ break
334
+ }
335
+ }
336
+
337
+ initPython () {
338
+ // Add loading indicator
339
+ this.overlay.show()
340
+ let script = document.createElement('script')
341
+ script.src = 'https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js'
342
+ script.onload = async () => {
343
+ this.pyodide = await loadPyodide({ indexURL : "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/" });
344
+ notyf.success('Loaded: Python')
345
+ log('Loaded python code:', res)
346
+ // Check if micropip is used
347
+ if (res.includes('micropip')) {
348
+ await this.pyodide.loadPackage('micropip')
349
+ log('Loaded micropip')
350
+ }
351
+ // Import packages if defined
352
+ if ('packages' in this.schema.model) {
353
+ await this.pyodide.loadPackage(this.schema.model.packages)
354
+ log('Loaded packages from schema')
355
+ } else {
356
+ await this.pyodide.loadPackagesFromImports(res)
357
+ log('Loaded packages from Python code')
358
+ }
359
+ this.overlay.hide()
360
+ }
361
+ document.head.appendChild(script)
362
+ }
363
+
364
+ initJS () {
365
+ // 1. String input <- loaded from url or code(string)
366
+ // 2. Target object (can be function, class or a function with async init <- code(object)
367
+ // 3. Model function
368
+
369
+ // We always start from 1 or 2
370
+ // For window execution we go: [1 ->] 2 -> 3
371
+ // For worker: [2 ->] 1 -> Worker
372
+
373
+ if (this.schema.model.worker) {
374
+ // Worker: Initialize worker with the model
375
+ if (typeof this.schema.model.code !== 'string') {
376
+ // 2 -> 1
377
+ log('Convert code in schema to string for WebWorker')
378
+ this.schema.model.code = this.schema.model.code.toString()
379
+ }
380
+ this.worker.postMessage(this.schema.model)
381
+ } else {
382
+ // Main: Initialize model in main window
383
+
384
+ // Target here represents raw JS object (e.g. class), not the final callable function
385
+ let target
386
+ if (typeof this.schema.model.code === 'string') {
387
+ // 1 -> 2
388
+ // Danger zone
389
+ if (this.schema.model.name) {
390
+ log('Evaluating code from string (has name)')
391
+ target = Function(
392
+ `${this.schema.model.code} ;return ${this.schema.model.name}`
393
+ )()
394
+ } else {
395
+ log('Evaluating code from string (no name)')
396
+ target = eval(`(${this.schema.model.code})`) // ( ͡° ͜ʖ ͡°) YEAHVAL
397
+ }
398
+ } else {
399
+ target = this.schema.model.code
400
+ }
401
+
402
+ // Need promise here in case of async init
403
+ Promise.resolve(utils.getModelFuncJS(this.schema.model, target, log))
404
+ .then(m => {
405
+ this.overlay.hide()
406
+ notyf.success('Loaded: JS model')
407
+ this.modelFunc = m
408
+ })
409
+ }
410
+ }
411
+
412
+ initAPI () {
413
+ this.overlay.hide()
414
+ if (this.schema.model.worker) {
415
+ // Worker:
416
+ this.worker.postMessage(this.schema.model)
417
+ } else {
418
+ // Main:
419
+ this.modelFunc = utils.getModelFuncAPI(model, log)
420
+ }
421
+ }
422
+
423
+ initTF () {
424
+ let script = document.createElement('script')
425
+ script.src = 'dist/tf.min.js'
426
+ script.onload = () => {
427
+ log('Loaded TF.js')
428
+ this.overlay.hide()
429
+ window['tf'].loadLayersModel(this.schema.model.url).then(res => {
430
+ log('Loaded Tensorflow model')
431
+ })
432
+ }
433
+ document.head.appendChild(script)
434
+ }
435
+
298
436
  run () {
299
437
  const schema = this.schema
300
438
  const data = this.data
@@ -306,7 +444,7 @@ export default class JSEE {
306
444
  log('Pass inputs as function arguments')
307
445
  inputValues = data.inputs.map(input => getValue(input))
308
446
  } else {
309
- log('Pass inputs in an object')
447
+ log('Pass inputs as object')
310
448
  inputValues = {}
311
449
  data.inputs.forEach(input => {
312
450
  if (input.name) {
@@ -326,7 +464,7 @@ export default class JSEE {
326
464
  data.inputs.forEach(input => {
327
465
  this.pyodide.globals.set(input.name, input.value);
328
466
  })
329
- this.pyodide.runPythonAsync(this.pymodel, () => {})
467
+ this.pyodide.runPythonAsync(this.schema.model.code, () => {})
330
468
  .then((res) => {
331
469
  if (schema.outputs && schema.outputs.length) {
332
470
  const resultObj = {}
@@ -349,6 +487,7 @@ export default class JSEE {
349
487
  case 'async-init':
350
488
  case 'async-function':
351
489
  case 'get':
490
+ case 'post':
352
491
  if (this.schema.model.worker) {
353
492
  this.worker.postMessage(inputValues)
354
493
  } else {
@@ -364,8 +503,6 @@ export default class JSEE {
364
503
  Promise.resolve(res).then(r => { this.output(r) })
365
504
  }
366
505
  break
367
- case 'api':
368
- break
369
506
  }
370
507
  }
371
508
 
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@jseeio/jsee",
3
- "version": "0.2.1",
3
+ "version": "0.2.5",
4
4
  "description": "",
5
5
  "main": "dist/jsee.js",
6
6
  "private": false,
7
7
  "scripts": {
8
- "build-dev": "webpack --mode=development --progress",
8
+ "build-dev": "webpack --mode=development --progress --stats-children",
9
9
  "build": "webpack --mode=production --progress && npx webpack --mode=production --progress --env RUNTIME",
10
- "watch": "nodemon --watch . --ignore dist --ext vue,js,css,html --exec 'npm run build-dev'",
11
- "prepublishOnly": "npm run build",
12
- "test": "tape test.js | faucet"
10
+ "watch": "nodemon --watch . --ignore dist --ext vue,js,css,html --exec 'npm run build-dev && npm test'",
11
+ "prepublishOnly": "npm run build && npm test",
12
+ "test": "jest test.js --detectOpenHandles",
13
+ "test-head": "HEADLESS=false npm test"
13
14
  },
14
15
  "author": "Anton Zemlyansky",
15
16
  "license": "MIT",
@@ -31,10 +32,14 @@
31
32
  "@babel/preset-env": "^7.16.5",
32
33
  "babel-loader": "^8.2.3",
33
34
  "css-loader": "^6.5.1",
35
+ "http-server": "^14.0.0",
36
+ "jest": "^27.4.5",
37
+ "jest-puppeteer": "^6.0.3",
34
38
  "node-sass": "^7.0.0",
35
39
  "nodemon": "^2.0.15",
36
- "puppeteer": "^1.12.2",
40
+ "puppeteer": "^1.20.0",
37
41
  "sass-loader": "^12.4.0",
42
+ "source-map-loader": "^3.0.0",
38
43
  "style-loader": "^3.3.1",
39
44
  "tape": "^4.9.1",
40
45
  "terser-webpack-plugin": "^5.3.0",