/** * Project : AMDA-NG * Name : MachineLearningUI.js * @class amdaUI.MachineLearningUI * @extends Ext.tab.Panel * @brief Machine Learning Module UI definition (View) * @author Benjamin RENARD * @version $Id: MachineLearningUI.js 1093 2022-01-14 15:54:26Z benjamin $ ****************************************************************************** * FT Id : Date : Name - Description ****************************************************************************** * : :14/01/2022: BRE - file creation */ Ext.define('amdaUI.MachineLearningUI', { extend: 'Ext.container.Container', alias: 'widget.panelMachineLearning', requires: [ 'amdaModel.MLModelObject', 'amdaModel.MachineLearningRun' ], modelTpl: new Ext.XTemplate( '<tpl for=".">', '<div class="ml-model-item">\ <h2 class="ml-model-item-name">{name}:{version}☑️</h2>\ </div>', '</tpl>' ), logs:"", predLogsCmp :null, modelUI: null, predictionUI: null, runModelObj: Ext.create('amdaModel.MachineLearningRun'), constructor: function(config) { this.init(config); this.callParent(arguments); }, selectModel: function(model) { var me = this; var mlModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.machinelearning.id); mlModule.getModelInfo(model.get('id'), function(modelinfo){ if (modelinfo.get('description').length > 0) { // Transform description into HTML var converter = new showdown.Converter(); modelinfo.set('description', converter.makeHtml(modelinfo.get('description'))); } me.modelUI.setModel(modelinfo); }); }, createPredictionUI: function() { var me = this; this.predictionUI = Ext.create('Ext.form.Panel', { items: [ { xtype: 'datefield', id: 'prediction-start', name: 'start', fieldLabel: 'Start Time', format: 'Y-m-d\\TH:i:s' }, { xtype: 'datefield', id: 'prediction-stop', name: 'stop', fieldLabel: 'Stop Time', format: 'Y-m-d\\TH:i:s' }, { xtype: 'fieldset', id: 'prediction-args', title: 'Input arguments', hidden: true }, { xtype: 'fieldset', id: 'prediction-hyperparameters', title: 'Hyper parameters', hidden: true, enable: false } ], setModel: function(modelinfo) { var defaultValues = modelinfo.get('defaults'); if (!defaultValues) defaultValues = {}; if (defaultValues['start']) me.predictionUI.queryById('prediction-start').setValue(defaultValues['start']); if (defaultValues['stop']) me.predictionUI.queryById('prediction-stop').setValue(defaultValues['stop']); var args = modelinfo.get('args'); if (!args) args = []; //me.predictionUI.queryById('prediction-args').setVisible(args.length > 0); //me.predictionUI.queryById('prediction-args').removeAll(); Ext.Array.each(args, function(arg) { if (arg == 'start' || arg == 'stop') { return; } var field = me.predictionUI.queryById('prediction-args').add({ xtype: 'textfield', fieldLabel: arg, name: arg, allowBlank: false }); if (defaultValues[arg]) { field.setValue(defaultValues[arg]); } }); var hyperparameters = modelinfo.get('hyperparameters'); if (!hyperparameters) hyperparameters = []; me.predictionUI.queryById('prediction-hyperparameters').setVisible(hyperparameters.length > 0); me.predictionUI.queryById('prediction-hyperparameters').removeAll(); Ext.Array.each(hyperparameters, function(hyperparam) { var field = me.predictionUI.queryById('prediction-hyperparameters').add({ xtype: 'textfield', fieldLabel: hyperparam, name: hyperparam, allowBlank: false }); if (defaultValues[hyperparam]) { field.setValue(defaultValues[hyperparam]); } }); } }); return this.predictionUI; }, createFittingUI: function() { this.fittingUI = Ext.create('Ext.form.Panel', { items: [ ], setModel: function(modelinfo) { } }); return this.fittingUI; }, createModelUI: function() { var me = this; this.predLogsCmp = new Ext.Component({ tpl:"<div>\ <h2 class='ml-pred-logs-titile'>PREDICTIONS: LOGS</h2>\ <div class='ml-pred-logs-content' id='prediction_logs'>{messages}</div>\ </div>", data: { messages:"" }, hidden: true }); this.modelUI = Ext.create('Ext.panel.Panel', { layout: 'border', items: [ { xtype: "component", bodyStyle: 'padding-left: 5px ;', autoScroll: true, id: "ml-model-info", region:'north', height: 200, tpl: '<div style="padding: 5px;"><h1>{name}</h1><p style="text-align: justify;">{description}</p></div>', }, { xtype: "tabpanel", region: "center", id: "ml-model-action", items: [ { title: "PREDICTION 📈 📉 📄 ", items: [ this.createPredictionUI(), me.predLogsCmp ], bbar: [ {xtype: 'button', cls:'ml-prediction', text: 'Run Model Prediction', handler: this.runPredictionRequest, scope: me} ] } /*, { title: "Fitting", items: [ this.createFittingUI() ], bbar: [ '->', {xtype: 'button', text: 'Run Fitting', handler: this.runFittingRequest, scope: me} ] }*/ ], setModel: function(modelinfo) { me.runModelObj.set('moduleId', modelinfo.get('id')); me.runModelObj.set('output', modelinfo.get('output')); var defaultValues = modelinfo.get('defaults'); if (!defaultValues) defaultValues = {}; this.items.each(function(item) { item.items.getAt(0).setModel(modelinfo); }); } } ], setModel: function(modelinfo) { this.queryById('ml-model-info').update(modelinfo.getData()); this.queryById('ml-model-action').setModel(modelinfo); } }); return this.modelUI; }, runPredictionRequest: function() { this.runRequest('prediction'); }, runFittingRequest: function() { this.runRequest('fitting'); }, runRequest: function(mode) { var currentUI = null; switch (mode) { case 'fitting': currentUI = this.fittingUI; myDesktopApp.errorMsg('Not available in this version'); return; case 'prediction': currentUI = this.predictionUI; break; } currentUI.getForm().updateRecord(this.runModelObj); this.runModelObj.set('mode', mode); var args = {}; if (currentUI.queryById(mode+'-args').isVisible()) { currentUI.queryById(mode+'-args').items.each(function (item) { args[item.name] = item.getValue(); }); } this.runModelObj.set('args', args); var hyperparameters = {}; if (currentUI.queryById(mode+'-hyperparameters').isVisible()) { currentUI.queryById(mode+'-hyperparameters').items.each(function (item) { hyperparameters[item.name] = item.getValue(); }); } this.runModelObj.set('hyperparameters', hyperparameters); loadMask.show(false); var me = this; AmdaAction.runMLModel(this.runModelObj.getJsonValues(), function (result, e) { console.log(e); loadMask.hide(); if (!e.status){ myDesktopApp.errorMsg('Internal error during request'); return; } if (!result.success){ myDesktopApp.errorMsg(result.message); return; } //new object to attach to new bkgJobNode var newobj = Ext.copyTo({}, me.runModelObj.getJsonValues(), me.runModelObj.propertiesToCopy); newobj.resultId = result.result; newobj.folderId = result.folder; newobj.processId = result.id; newobj.tabId = result.tabId; newobj.name = result.name; newobj.request_obj = result.request_obj; newobj = Ext.create(me.runModelObj.$className, newobj); //create bkgJobNode var newNode = Ext.create('amdaModel.BkgJobNode', { info : result.info, jobType : 'machinelearning', processId : result.id, id : result.id, text : result.name, status : result.status, start : result.start, stop : result.stop, tabId : result.tabId, leaf : true, object : newobj }); //attach bkgJobNode to explorer switch (result.status) { case amdaModel.BkgJobNode.STATUS_LIST.DONE : newNode.createJobNode(true); newNode.editNode(true, false); break; case amdaModel.BkgJobNode.STATUS_LIST.IN_PROGRESS : newNode.createJobNode(false); break; default: newNode.createJobNode(true); } }); }, getDefaultModelsDataView: function() { var modelStore = Ext.create('Ext.data.Store', { fields: [ {name: 'id', type: 'string'}, {name: 'name', type: 'string'}, {name: 'version', type: 'string'} ], autoLoad: true, proxy: { type: 'direct', api: {read: AmdaAction.readDefaultMLModels}, reader: { type: 'json', root: 'result', totalProperty: 'totalCount' } } }); return { xtype: "dataview", store: modelStore, tpl: this.modelTpl, trackOver: true, overItemCls: 'ml-model-item-over', itemSelector: 'div.ml-model-item', autoScroll : true, emptyText: 'No models available', listeners : { itemclick: function( dataview, record, item, index, e, eOpts ) { this.selectModel(record); }, scope: this } }; }, getUserModelsDataView: function() { return { xtype: "dataview", store: Ext.create('Ext.data.Store', { model: 'amdaModel.MLModelObject' }), tpl: this.modelTpl, itemSelector: 'div.ml-model-wrap', emptyText: 'No models available' }; }, init: function(config) { var me = this; var myConf = { plain: true, width: 800, height: 600, layout: 'border', items: [ { xtype: "panel", region:'west', width: 200, layout: { type: 'accordion', titleCollapse: true, animate: true, activeOnTop: true }, items: [ { title: '📌 DEFAULT MODELS 📋', items: [ this.getDefaultModelsDataView() ] }/*, { title: 'User Models', items: [ this.getUserModelsDataView() ] }*/ ], }, { xtype: "panel", region: 'center', layout: 'fit', items: [ this.createModelUI() ] } ], listeners: { afterrender: function() { me.setSocket(); } } }; Ext.apply (this, Ext.apply (arguments, myConf)); }, setSocket: function(){ const me = this; AmdaAction.getMLConfig(function (result, e) { if (!e.status){ return; } if (!result.success){ return; } if (result.entrypoint) { me.predLogsCmp.setVisible(true); const endPoint = result.entrypoint; const socket = io.connect(`${endPoint}`); const typeMsg = "running"; socket.emit(typeMsg, "I'm connected"); socket.on(typeMsg, (msg) => { const txt = msg.data; me.logs+= "<p>"+ txt+"</p>"; me.predLogsCmp.update({messages:me.logs}); }); } }); }, });