@jseeio/jsee 0.2.2 → 0.2.6

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,191 +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
207
  // Check inputs
208
+ // Relies on model.code
209
+ // So run after possible fetching
114
210
  if (typeof schema.inputs === 'undefined') {
115
- schema.inputs = []
211
+ schema.model.container = 'args'
212
+ schema.inputs = getInputs(schema.model)
116
213
  }
117
214
 
118
- // Check if name is present, if not - get name from the file
119
- if (typeof schema.model.name === 'undefined') {
120
- // Two options here
121
- if (schema.model.url) {
122
- // 1. Get the name from the file name
123
- schema.model.name = schema.model.url.split('/').pop().split('.')[0]
124
- log('Use name from url: ', schema.model.name)
125
- } else if (schema.model.code) {
126
- // 2. Get the name from the url
127
- schema.model.name = schema.model.code.name
128
- log('Use name from code: ', schema.model.name)
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'
129
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)
130
232
  }
131
233
 
234
+ // At this point we have all code in model.code or api
132
235
  this.schema = clone(schema)
236
+ }
133
237
 
134
- // Init Vue app
135
- this.app = createVueApp(this, this.schema, (container) => {
238
+ initVue () {
239
+ log('Initializing VUE')
240
+ this.app = createVueApp(this, (container) => {
136
241
  // Called when the app is mounted
137
242
  // FYI "this" here refers to port object
138
243
  this.outputsContainer = container.querySelector('#outputs')
139
244
  this.inputsContainer = container.querySelector('#inputs')
140
245
  this.modelContainer = container.querySelector('#model')
141
-
142
246
  // Init overlay
143
247
  this.overlay = new Overlay(this.inputsContainer ? this.inputsContainer : this.outputsContainer)
144
- })
248
+ }, log)
145
249
  this.data = this.app.$data
250
+ }
146
251
 
147
- // Init Model
148
- // ----------
149
- if (this.schema.model.type === 'py') {
150
- // Add loading indicator
151
- this.overlay.show()
152
- let script = document.createElement('script')
153
- script.src = 'https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js'
154
- script.onload = async () => {
155
- this.pyodide = await loadPyodide({ indexURL : "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/" });
156
- notyf.success('Loaded: Python')
157
- const resRaw = await fetch(this.schema.model.url)
158
- const res = await resRaw.text()
159
- this.pymodel = res
160
- log('Loaded python code:', res)
161
- // Check if micropip is used
162
- if (res.includes('micropip')) {
163
- await this.pyodide.loadPackage('micropip')
164
- log('Loaded micropip')
165
- }
166
- // Import packages if defined
167
- if ('packages' in this.schema.model) {
168
- await this.pyodide.loadPackage(this.schema.model.packages)
169
- log('Loaded packages from schema')
170
- } else {
171
- await this.pyodide.loadPackagesFromImports(res)
172
- log('Loaded packages from Python code')
173
- }
252
+ initWorker () {
253
+ if (this.schema.model.worker) {
254
+ log('Initializing Worker')
255
+ this.worker = new Worker()
256
+ this.worker.onmessage = (e) => {
174
257
  this.overlay.hide()
175
- }
176
- document.head.appendChild(script)
177
- } else if (['function', 'class', 'async-init', 'async-function'].includes(this.schema.model.type)) {
178
- // Initialize worker with the model
179
- if (this.schema.model.worker) {
180
- // this.worker = new Worker(new URL('./src/worker.js', import.meta.url))
181
- this.worker = new Worker()
182
- if (this.schema.model.url) {
183
- fetch(this.schema.model.url)
184
- .then(res => res.text())
185
- .then(res => {
186
- log('Loaded js code for worker')
187
- this.schema.model.code = res
188
- this.worker.postMessage(this.schema.model)
189
- })
190
- } else if (typeof this.schema.model.code !== 'undefined') {
191
- this.worker.postMessage(this.schema.model)
192
- } else {
193
- notyf.error('No code provided')
194
- }
195
-
196
- this.worker.onmessage = (e) => {
197
- this.overlay.hide()
198
- const res = e.data
199
- if ((typeof res === 'object') && (res._status)) {
200
- switch (res._status) {
201
- case 'loaded':
202
- notyf.success('Loaded: JS model (in worker)')
203
- break
204
- case 'log':
205
- log(...res._log)
206
- break
207
- }
208
- } else {
209
- log('Response from worker:', res)
210
- this.output(res)
211
- }
212
- }
213
- this.worker.onerror = (e) => {
214
- this.overlay.hide()
215
- notyf.error(e.message)
216
- log('Error from worker:', e)
217
- }
218
- } else {
219
- // Initialize model in main window
220
- log('Init model in window')
221
- let script = document.createElement('script')
222
- script.src = this.schema.model.url
223
- script.onload = () => {
224
- notyf.success('Loaded: JS model')
225
- this.overlay.hide()
226
- log('Loaded JS model in main window')
227
-
228
- // Initializing the model (same in worker)
229
- if (this.schema.model.type === 'class') {
230
- log('Init class')
231
- const modelClass = new window[this.schema.model.name]()
232
- this.modelFunc = (...a) => {
233
- return modelClass[this.schema.model.method || 'predict'](...a)
234
- }
235
- } else if (this.schema.model.type === 'async-init') {
236
- log('Init function with promise')
237
- window[this.schema.model.name]().then((m) => {
238
- log('Async init resolved: ', m)
239
- this.modelFunc = m
240
- })
241
- } else {
242
- log('Init function')
243
- 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
244
267
  }
268
+ } else {
269
+ log('Response from worker:', res)
270
+ this.output(res)
245
271
  }
246
- document.head.appendChild(script)
247
272
  }
248
- } else if (this.schema.model.type === 'tf') {
249
- // Initialize TF
250
- let script = document.createElement('script')
251
- script.src = 'dist/tf.min.js'
252
- script.onload = () => {
253
- log('Loaded TF.js')
273
+ this.worker.onerror = (e) => {
254
274
  this.overlay.hide()
255
- window['tf'].loadLayersModel(this.schema.model.url).then(res => {
256
- log('Loaded Tensorflow model')
257
- })
258
- }
259
- document.head.appendChild(script)
260
- } else if (this.schema.model.type === 'get') {
261
- this.overlay.hide()
262
- this.modelFunc = (data) => {
263
- const query = new window['URLSearchParams'](data).toString()
264
- log('Generated query string:', query)
265
- const resPromise = fetch(this.schema.model.url +'?' + query)
266
- .then(response => response.json())
267
- return resPromise
275
+ notyf.error(e.message)
276
+ log('Error from worker:', e)
268
277
  }
269
278
  }
279
+ }
270
280
 
271
- // Init render
272
- // -----------
281
+ initRender () {
273
282
  if (this.schema.render && this.schema.render.url) {
274
- log('Init render in window')
283
+ log('Initializing a render function')
275
284
  let script = document.createElement('script')
276
285
  script.src = this.schema.render.url
277
286
  script.onload = () => {
@@ -300,6 +309,130 @@ export default class JSEE {
300
309
  }
301
310
  }
302
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
+
303
436
  run () {
304
437
  const schema = this.schema
305
438
  const data = this.data
@@ -311,7 +444,7 @@ export default class JSEE {
311
444
  log('Pass inputs as function arguments')
312
445
  inputValues = data.inputs.map(input => getValue(input))
313
446
  } else {
314
- log('Pass inputs in an object')
447
+ log('Pass inputs as object')
315
448
  inputValues = {}
316
449
  data.inputs.forEach(input => {
317
450
  if (input.name) {
@@ -331,7 +464,7 @@ export default class JSEE {
331
464
  data.inputs.forEach(input => {
332
465
  this.pyodide.globals.set(input.name, input.value);
333
466
  })
334
- this.pyodide.runPythonAsync(this.pymodel, () => {})
467
+ this.pyodide.runPythonAsync(this.schema.model.code, () => {})
335
468
  .then((res) => {
336
469
  if (schema.outputs && schema.outputs.length) {
337
470
  const resultObj = {}
@@ -354,6 +487,7 @@ export default class JSEE {
354
487
  case 'async-init':
355
488
  case 'async-function':
356
489
  case 'get':
490
+ case 'post':
357
491
  if (this.schema.model.worker) {
358
492
  this.worker.postMessage(inputValues)
359
493
  } else {
@@ -369,8 +503,6 @@ export default class JSEE {
369
503
  Promise.resolve(res).then(r => { this.output(r) })
370
504
  }
371
505
  break
372
- case 'api':
373
- break
374
506
  }
375
507
  }
376
508
 
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@jseeio/jsee",
3
- "version": "0.2.2",
3
+ "version": "0.2.6",
4
4
  "description": "",
5
5
  "main": "dist/jsee.js",
6
6
  "private": false,
7
7
  "scripts": {
8
- "build-dev": "webpack --mode=development --progress",
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"
8
+ "build-dev": "webpack --mode=development --progress --stats-children --env DEVELOPMENT",
9
+ "build": "webpack --mode=production --progress && webpack --mode=production --progress --env RUNTIME",
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",