aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--backend/api/api/Controllers/ModelController.cs12
-rw-r--r--backend/api/api/Controllers/PredictorController.cs30
-rw-r--r--backend/api/api/Controllers/UserController.cs3
-rw-r--r--backend/api/api/Models/Model.cs7
-rw-r--r--backend/api/api/Services/DatasetService.cs5
-rw-r--r--backend/api/api/Services/IDatasetService.cs1
-rw-r--r--backend/api/api/Services/IMlConnectionService.cs2
-rw-r--r--backend/api/api/Services/IModelService.cs1
-rw-r--r--backend/api/api/Services/IPredictorService.cs1
-rw-r--r--backend/api/api/Services/IUserService.cs2
-rw-r--r--backend/api/api/Services/MlConnectionService.cs18
-rw-r--r--backend/api/api/Services/ModelService.cs5
-rw-r--r--backend/api/api/Services/PredictorService.cs5
-rw-r--r--backend/api/api/Services/UserService.cs51
-rw-r--r--backend/microservice/PythonServer/project/socket_example/socket/client.py (renamed from backend/microservice/PythonServer/project/api/socket/client.py)0
-rw-r--r--backend/microservice/PythonServer/project/socket_example/socket/server.py (renamed from backend/microservice/PythonServer/project/api/socket/server.py)0
-rw-r--r--backend/microservice/PythonServer/project/socket_example/socket2/client.py (renamed from backend/microservice/PythonServer/project/api/socket2/client.py)0
-rw-r--r--backend/microservice/PythonServer/project/socket_example/socket2/server.py (renamed from backend/microservice/PythonServer/project/api/socket2/server.py)0
-rw-r--r--backend/microservice/api/controller.py42
-rw-r--r--backend/microservice/api/ml_service.py155
-rw-r--r--backend/microservice/api/ml_socket.py (renamed from backend/microservice/ml_socket.py)13
-rw-r--r--frontend/package-lock.json303
-rw-r--r--frontend/package.json4
-rw-r--r--frontend/src/app/_data/Model.ts24
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.css4
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.html5
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.ts47
-rw-r--r--frontend/src/app/_elements/item-predictor/item-predictor.component.html2
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.css0
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.html1
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/reactive-background/reactive-background.component.ts167
-rw-r--r--frontend/src/app/_pages/add-model/add-model.component.html82
-rw-r--r--frontend/src/app/_pages/add-model/add-model.component.ts62
-rw-r--r--frontend/src/app/_pages/home/home.component.html4
-rw-r--r--frontend/src/app/_pages/home/home.component.ts35
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.html4
-rw-r--r--frontend/src/app/_services/datasets.service.ts6
-rw-r--r--frontend/src/app/_services/home.service.spec.ts16
-rw-r--r--frontend/src/app/_services/home.service.ts9
-rw-r--r--frontend/src/app/_services/models.service.ts18
-rw-r--r--frontend/src/app/_services/predictors.service.ts2
-rw-r--r--frontend/src/app/_services/web-socket.service.ts6
-rw-r--r--frontend/src/app/app.component.html1
-rw-r--r--frontend/src/app/app.module.ts2
-rw-r--r--frontend/src/styles.css3
48 files changed, 1073 insertions, 141 deletions
diff --git a/.gitignore b/.gitignore
index d094e2e2..25a7cdac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@ sandbox/test-projekat-danijel/backend/.vs/
sandbox/testAppSonja/MiniApkSonja/MiniApkSonja/bin/
sandbox/testAppSonja/MiniApkSonja/MiniApkSonja/obj/
sandbox/TestTamara/TestTamara/TestTamara/obj/
-sandbox/TestTamara/TestTamara/TestTamara/bin/ \ No newline at end of file
+sandbox/TestTamara/TestTamara/TestTamara/bin/
+backend/microservice/temp/
+backend/microservice/api/__pycache__/
diff --git a/backend/api/api/Controllers/ModelController.cs b/backend/api/api/Controllers/ModelController.cs
index b997efa3..4bc094cd 100644
--- a/backend/api/api/Controllers/ModelController.cs
+++ b/backend/api/api/Controllers/ModelController.cs
@@ -14,22 +14,28 @@ namespace api.Controllers
{
private IMlConnectionService _mlService;
+ private readonly IDatasetService _datasetService;
+ private readonly IFileService _fileService;
private readonly IModelService _modelService;
private JwtToken jwtToken;
- public ModelController(IMlConnectionService mlService, IModelService modelService, IConfiguration configuration)
+ public ModelController(IMlConnectionService mlService, IModelService modelService, IDatasetService datasetService, IFileService fileService, IConfiguration configuration)
{
_mlService = mlService;
_modelService = modelService;
+ _datasetService = datasetService;
+ _fileService = fileService;
jwtToken = new JwtToken(configuration);
}
[HttpPost("sendModel")]
[Authorize(Roles = "User")]
- public async Task<ActionResult<string>> Test([FromBody] object model)
+ public async Task<ActionResult<string>> Test([FromBody] Model model)
{
- var result = await _mlService.SendModelAsync(model);
+ var dataset = _datasetService.GetOneDataset(model.datasetId);
+ var filepath = _fileService.GetFilePath(dataset.fileId, dataset.username);
+ var result = await _mlService.SendModelAsync(model, filepath);
return Ok(result);
}
diff --git a/backend/api/api/Controllers/PredictorController.cs b/backend/api/api/Controllers/PredictorController.cs
index 7f8f1692..63c5d2bf 100644
--- a/backend/api/api/Controllers/PredictorController.cs
+++ b/backend/api/api/Controllers/PredictorController.cs
@@ -74,6 +74,36 @@ namespace api.Controllers
return _predictorService.SearchPredictors(name, username);
}
+ //SEARCH za predictore (public ili private sa ovim imenom )
+ // GET api/<PredictorController>/search/{name}
+ [HttpGet("{id}")]
+ [Authorize(Roles = "User")]
+ public ActionResult<Predictor> GetPredictor(string id)
+ {
+ string username;
+ var header = Request.Headers[HeaderNames.Authorization];
+ if (AuthenticationHeaderValue.TryParse(header, out var headerValue))
+ {
+ var scheme = headerValue.Scheme;
+ var parameter = headerValue.Parameter;
+ username = jwtToken.TokenToUsername(parameter);
+ if (username == null)
+ return null;
+ }
+ else
+ return BadRequest();
+
+ //ako bude trebao ID, samo iz baze uzeti
+
+ Predictor predictor = _predictorService.GetPredictor(username, id);
+
+ if (predictor == null)
+ return NotFound($"Predictor with id = {id} not found");
+
+ return predictor;
+ }
+
+
//da li da se odvoji search za public i posebno za private?
// GET api/<PredictorController>/{name}
[HttpGet("{name}")]
diff --git a/backend/api/api/Controllers/UserController.cs b/backend/api/api/Controllers/UserController.cs
index 0287f3cb..741382b8 100644
--- a/backend/api/api/Controllers/UserController.cs
+++ b/backend/api/api/Controllers/UserController.cs
@@ -135,8 +135,7 @@ namespace api.Controllers
else
return BadRequest();
- userService.Update(username, user);
- return NoContent();
+ return Ok(userService.Update(username, user));
}
// DELETE api/<UserController>/5
diff --git a/backend/api/api/Models/Model.cs b/backend/api/api/Models/Model.cs
index 5678daaf..2baab1c0 100644
--- a/backend/api/api/Models/Model.cs
+++ b/backend/api/api/Models/Model.cs
@@ -38,10 +38,13 @@ namespace api.Models
public int batchSize { get; set; }
// na izlazu je moguce da bude vise neurona (klasifikacioni problem sa vise od 2 klase)
public int outputNeurons { get; set; }
- public string inputLayerActivationFunction { get; set; }
- public string hiddenLayerActivationFunction { get; set; }
+ public string[] hiddenLayerActivationFunctions { get; set; }
public string outputLayerActivationFunction { get; set; }
+ public string[] metrics { get; set; }
+ public int epochs { get; set; }
+ public string nullValues { get; set; }
+ public string[] nullValuesReplacers { get; set; }
}
}
diff --git a/backend/api/api/Services/DatasetService.cs b/backend/api/api/Services/DatasetService.cs
index ab19935d..2ff271f3 100644
--- a/backend/api/api/Services/DatasetService.cs
+++ b/backend/api/api/Services/DatasetService.cs
@@ -68,6 +68,11 @@ namespace api.Services
}
//odraditi za pretragu getOne
+ public Dataset GetOneDataset(string id)
+ {
+ return _dataset.Find(dataset => dataset._id == id).FirstOrDefault();
+ }
+
//ako je potrebno da se zameni name ili ekstenzija
public void Update(string username, string name, Dataset dataset)
{
diff --git a/backend/api/api/Services/IDatasetService.cs b/backend/api/api/Services/IDatasetService.cs
index 9beec400..8e62ba43 100644
--- a/backend/api/api/Services/IDatasetService.cs
+++ b/backend/api/api/Services/IDatasetService.cs
@@ -6,6 +6,7 @@ namespace api.Services
public interface IDatasetService
{
Dataset GetOneDataset(string username, string name);
+ Dataset GetOneDataset(string id);
List<Dataset> SearchDatasets(string name, string username);
List<Dataset> GetMyDatasets(string username);
List<Dataset> SortDatasets(string username, bool ascdsc, int latest);
diff --git a/backend/api/api/Services/IMlConnectionService.cs b/backend/api/api/Services/IMlConnectionService.cs
index f38fb50a..ee839d28 100644
--- a/backend/api/api/Services/IMlConnectionService.cs
+++ b/backend/api/api/Services/IMlConnectionService.cs
@@ -3,6 +3,6 @@ namespace api.Services
{
public interface IMlConnectionService
{
- Task<string> SendModelAsync(object model);
+ Task<string> SendModelAsync(object model, object dataset);
}
} \ No newline at end of file
diff --git a/backend/api/api/Services/IModelService.cs b/backend/api/api/Services/IModelService.cs
index ee5c279f..637d09a3 100644
--- a/backend/api/api/Services/IModelService.cs
+++ b/backend/api/api/Services/IModelService.cs
@@ -6,6 +6,7 @@ namespace api.Services
public interface IModelService
{
Model GetOneModel(string username, string name);
+ Model GetOneModel(string id);
List<Model> GetMyModels(string username);
List<Model> GetLatestModels(string username);
//List<Model> GetPublicModels();
diff --git a/backend/api/api/Services/IPredictorService.cs b/backend/api/api/Services/IPredictorService.cs
index 2017add2..729dd0b6 100644
--- a/backend/api/api/Services/IPredictorService.cs
+++ b/backend/api/api/Services/IPredictorService.cs
@@ -6,6 +6,7 @@ namespace api.Services
public interface IPredictorService
{
Predictor GetOnePredictor(string username, string name);
+ Predictor GetPredictor(string username, string GetPredictor);
List<Predictor> SearchPredictors(string name, string username);
List<Predictor> GetMyPredictors(string username);
List<Predictor> SortPredictors(string username, bool ascdsc, int latest);
diff --git a/backend/api/api/Services/IUserService.cs b/backend/api/api/Services/IUserService.cs
index 1cb6a609..e4a23213 100644
--- a/backend/api/api/Services/IUserService.cs
+++ b/backend/api/api/Services/IUserService.cs
@@ -8,7 +8,7 @@ namespace api.Services
List<User> Get();// daje sve korisnike
User GetUserUsername(string username); //daje korisnika po korisnickom imenu
User Create(User user); // kreira korisnika
- void Update(string username, User user); //apdejtuje korisnika po idu
+ bool Update(string username, User user); //apdejtuje korisnika po idu
void Delete(string username);//brise korisnika
}
}
diff --git a/backend/api/api/Services/MlConnectionService.cs b/backend/api/api/Services/MlConnectionService.cs
index 9b167537..9c3b3fd8 100644
--- a/backend/api/api/Services/MlConnectionService.cs
+++ b/backend/api/api/Services/MlConnectionService.cs
@@ -6,13 +6,19 @@ namespace api.Services
{
public class MlConnectionService : IMlConnectionService
{
- public async Task<string> SendModelAsync(object model)
+ private RestClient client;
+
+ public MlConnectionService()
+ {
+ this.client = new RestClient("http://127.0.0.1:5543");
+ }
+
+ public async Task<string> SendModelAsync(object model, object dataset)
{
- RestClient client = new RestClient("http://localhost:5000");
- var request = new RestRequest("data", Method.Post);
- request.AddJsonBody(model);
- var result = await client.ExecuteAsync(request);
- return result.Content;//Response od ML microservisa
+ var request = new RestRequest("train", Method.Post);
+ request.AddJsonBody(new { model, dataset});
+ var result = await this.client.ExecuteAsync(request);
+ return result.Content; //Response od ML microservisa
}
}
}
diff --git a/backend/api/api/Services/ModelService.cs b/backend/api/api/Services/ModelService.cs
index f42219f5..eae8c78b 100644
--- a/backend/api/api/Services/ModelService.cs
+++ b/backend/api/api/Services/ModelService.cs
@@ -50,6 +50,11 @@ namespace api.Services
return _model.Find(model => model.username == username && model.name == name).FirstOrDefault();
}
+ public Model GetOneModel(string id)
+ {
+ return _model.Find(model => model._id == id).FirstOrDefault();
+ }
+
public void Update(string username, string name, Model model)
{
_model.ReplaceOne(model => model.username == username && model.name == name, model);
diff --git a/backend/api/api/Services/PredictorService.cs b/backend/api/api/Services/PredictorService.cs
index 05860126..01bc8359 100644
--- a/backend/api/api/Services/PredictorService.cs
+++ b/backend/api/api/Services/PredictorService.cs
@@ -40,6 +40,11 @@ namespace api.Services
return _predictor.Find(predictor => predictor.username == username && predictor.name == name).FirstOrDefault();
}
+ public Predictor GetPredictor(string username, string id)
+ {
+ return _predictor.Find(predictor => predictor.username == username && predictor._id == id).FirstOrDefault();
+
+ }
//last private models
public List<Predictor> SortPredictors(string username, bool ascdsc, int latest)
{
diff --git a/backend/api/api/Services/UserService.cs b/backend/api/api/Services/UserService.cs
index f613f923..607bb04b 100644
--- a/backend/api/api/Services/UserService.cs
+++ b/backend/api/api/Services/UserService.cs
@@ -7,11 +7,22 @@ namespace api.Services
public class UserService : IUserService
{
private readonly IMongoCollection<User> _users;
+ private readonly IMongoClient _client;
+ private readonly IMongoCollection<Model> _models;
+ private readonly IMongoCollection<Dataset> _datasets;
+ private readonly IMongoCollection<FileModel> _fileModels;
+ private readonly IMongoCollection<Predictor> _predictors;
+
public UserService(IUserStoreDatabaseSettings settings, IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase(settings.DatabaseName);
_users = database.GetCollection<User>(settings.CollectionName);
+ _models = database.GetCollection<Model>(settings.ModelCollectionName);
+ _datasets= database.GetCollection<Dataset>(settings.DatasetCollectionName);
+ _fileModels = database.GetCollection<FileModel>(settings.FilesCollectionName);
+ _predictors= database.GetCollection<Predictor>(settings.PredictorCollectionName);
+ _client = mongoClient;
}
public User Create(User user)
{
@@ -26,10 +37,46 @@ namespace api.Services
{
return _users.Find(user => user.Username == username).FirstOrDefault();
}
- public void Update(string username, User user)
+ public bool Update(string username, User user)
{
//username koji postoji u bazi
- _users.ReplaceOne(user => user.Username == username, user);
+ using (var session = _client.StartSession())
+ {
+
+ if(_users.Find(u => u.Username == user.Username).FirstOrDefault()!=null)
+ {
+ return false;
+ }
+
+ //Trenutan MongoDB Server ne podrzava transakcije.Omoguciti Podrsku
+ //session.StartTransaction();
+ try
+ {
+ _users.ReplaceOne(user => user.Username == username, user);
+ if (username != user.Username)
+ {
+ var builderModel = Builders<Model>.Update;
+ var builderDataset = Builders<Dataset>.Update;
+ var builderFileModel = Builders<FileModel>.Update;
+ var builderPredictor = Builders<Predictor>.Update;
+ _models.UpdateMany(x => x.username == username, builderModel.Set(x => x.username, user.Username));
+ _datasets.UpdateMany(x => x.username == username, builderDataset.Set(x => x.username, user.Username));
+ _fileModels.UpdateMany(x => x.username == username, builderFileModel.Set(x => x.username, user.Username));
+ _predictors.UpdateMany(x => x.username == username, builderPredictor.Set(x => x.username, user.Username));
+ }
+
+ //session.AbortTransaction();
+
+
+ //session.CommitTransaction();
+ }
+ catch (Exception e)
+ {
+ //session.AbortTransaction();
+ return false;
+ }
+ return true;
+ }
}
public void Delete(string username)
{
diff --git a/backend/microservice/PythonServer/project/api/socket/client.py b/backend/microservice/PythonServer/project/socket_example/socket/client.py
index d5740e25..d5740e25 100644
--- a/backend/microservice/PythonServer/project/api/socket/client.py
+++ b/backend/microservice/PythonServer/project/socket_example/socket/client.py
diff --git a/backend/microservice/PythonServer/project/api/socket/server.py b/backend/microservice/PythonServer/project/socket_example/socket/server.py
index d6ff3f7c..d6ff3f7c 100644
--- a/backend/microservice/PythonServer/project/api/socket/server.py
+++ b/backend/microservice/PythonServer/project/socket_example/socket/server.py
diff --git a/backend/microservice/PythonServer/project/api/socket2/client.py b/backend/microservice/PythonServer/project/socket_example/socket2/client.py
index 65e76b55..65e76b55 100644
--- a/backend/microservice/PythonServer/project/api/socket2/client.py
+++ b/backend/microservice/PythonServer/project/socket_example/socket2/client.py
diff --git a/backend/microservice/PythonServer/project/api/socket2/server.py b/backend/microservice/PythonServer/project/socket_example/socket2/server.py
index c65dae78..c65dae78 100644
--- a/backend/microservice/PythonServer/project/api/socket2/server.py
+++ b/backend/microservice/PythonServer/project/socket_example/socket2/server.py
diff --git a/backend/microservice/api/controller.py b/backend/microservice/api/controller.py
new file mode 100644
index 00000000..ceed02ad
--- /dev/null
+++ b/backend/microservice/api/controller.py
@@ -0,0 +1,42 @@
+import flask
+from flask import request, jsonify
+import ml_socket
+import ml_service
+import tensorflow as tf
+import pandas as pd
+
+app = flask.Flask(__name__)
+app.config["DEBUG"] = True
+app.config["SERVER_NAME"] = "127.0.0.1:5543"
+
+class train_callback(tf.keras.callbacks.Callback):
+ def __init__(self, x_test, y_test):
+ self.x_test = x_test
+ self.y_test = y_test
+ #
+ def on_epoch_end(self, epoch, logs=None):
+ print(epoch)
+ #print('Evaluation: ', self.model.evaluate(self.x_test,self.y_test),"\n") #broj parametara zavisi od izabranih metrika loss je default
+
+@app.route('/train', methods = ['POST'])
+def train():
+ print("******************************TRAIN*************************************************")
+ f = request.json["dataset"]
+ dataset = pd.read_csv(f)
+ #
+ result = ml_service.train(dataset, request.json["model"], train_callback)
+ print(result)
+ return jsonify(result)
+
+@app.route('/predict', methods = ['POST'])
+def predict():
+ f = request.json['filepath']
+ dataset = pd.read_csv(f)
+ m = request.json['modelpath']
+ #model = tf.keras.models.load_model(m)
+ #
+ #model.predict?
+
+print("App loaded.")
+ml_socket.start()
+app.run() \ No newline at end of file
diff --git a/backend/microservice/api/ml_service.py b/backend/microservice/api/ml_service.py
new file mode 100644
index 00000000..efd24fdc
--- /dev/null
+++ b/backend/microservice/api/ml_service.py
@@ -0,0 +1,155 @@
+import pandas as pd
+import tensorflow as tf
+import keras
+import numpy as np
+import csv
+import json
+import h5py
+import sklearn.metrics as sm
+from statistics import mode
+from typing_extensions import Self
+from copyreg import constructor
+from flask import request, jsonify, render_template
+from sklearn.preprocessing import LabelEncoder
+from sklearn.preprocessing import StandardScaler
+from sklearn.model_selection import train_test_split
+from dataclasses import dataclass
+
+@dataclass
+class TrainingResult:
+ accuracy: float
+ precision: float
+ recall: float
+ tn: float
+ fp: float
+ fn: float
+ tp: float
+ specificity: float
+ f1: float
+ mse: float
+ mae: float
+ mape: float
+ rmse: float
+ fpr: float
+ tpr: float
+
+def train(dataset, params, callback):
+ data = pd.DataFrame()
+ for col in params["inputColumns"]:
+ data[col]=dataset[col]
+ output_column = params["columnToPredict"]
+ data[output_column] = dataset[output_column]
+ #
+ # Brisanje null kolona / redova / zamena
+ #nullreplace=[
+ # {"column":"Embarked","value":"C","deleteRow":false,"deleteCol":true},
+ # {"column": "Cabin","value":"C123","deleteRow":"0","deleteCol":"0"}]
+
+ null_value_options = params["nullValues"]
+ null_values_replacers = params["nullValuesReplacers"]
+
+ if(null_value_options=='replace'):
+ print("replace null") # TODO
+ elif(null_value_options=='delete_rows'):
+ data=data.dropna()
+ elif(null_value_options=='delete_columns'):
+ data=data.dropna()
+ #
+ #print(data.isnull().any())
+ #
+ # Brisanje kolona koje ne uticu na rezultat
+ #
+ num_rows=data.shape[0]
+ for col in data.columns:
+ if((data[col].nunique()==(num_rows)) and (data[col].dtype==np.object_)):
+ data.pop(col)
+ #
+ # Enkodiranje
+ #
+ encoding=params["encoding"]
+ if(encoding=='label'):
+ encoder=LabelEncoder()
+ for col in data.columns:
+ if(data[col].dtype==np.object_):
+ data[col]=encoder.fit_transform(data[col])
+ elif(encoding=='onehot'):
+ category_columns=[]
+ for col in data.columns:
+ if(data[col].dtype==np.object_):
+ category_columns.append(col)
+ data=pd.get_dummies(data, columns=category_columns, prefix=category_columns)
+ #
+ # Input - output
+ #
+ x_columns = []
+ for col in data.columns:
+ if(col!=output_column):
+ x_columns.append(col)
+ x = data[x_columns].values
+ y = data[output_column].values
+ #
+ # Podela na test i trening skupove
+ #
+ test=params["randomTestSetDistribution"]
+ randomOrder = params["randomOrder"]
+ if(randomOrder):
+ random=50
+ else:
+ random=0
+ x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=test, random_state=random)
+ #
+ # Skaliranje vrednosti
+ #
+ scaler=StandardScaler()
+ scaler.fit(x_train)
+ x_test=scaler.transform(x_test)
+ x_train=scaler.transform(x_train)
+ #
+ # Treniranje modela
+ #
+ classifier=tf.keras.Sequential()
+ hidden_layer_neurons = params["hiddenLayerNeurons"]
+ for func in params["hiddenLayerActivationFunctions"]:
+ classifier.add(tf.keras.layers.Dense(units=hidden_layer_neurons,activation=func))
+ output_func = params["outputLayerActivationFunction"]
+ classifier.add(tf.keras.layers.Dense(units=1,activation=output_func))
+ optimizer = params["optimizer"]
+ metrics=params['metrics']
+ loss_func=params["lossFunction"]
+ classifier.compile(optimizer=optimizer, loss=loss_func,metrics=metrics)
+ batch_size = params["batchSize"]
+ epochs = params["epochs"]
+ history=classifier.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, callbacks=callback(x_test, y_test), validation_split=0.2) # TODO params["validationSplit"]
+ #
+ # Test
+ #
+ y_pred=classifier.predict(x_test)
+ y_pred=(y_pred>=0.5).astype('int')
+ #y_pred=(y_pred * 100).astype('int')
+ y_pred=y_pred.flatten()
+ result=pd.DataFrame({"Actual":y_test,"Predicted":y_pred})
+ model_name = params['_id']
+ classifier.save("temp/"+model_name, save_format='h5')
+ #
+ # Metrike
+ #
+ print("HELLO???")
+ print(result)
+ print("HELLO???")
+ accuracy = float(sm.accuracy_score(y_test,y_pred))
+ precision = float(sm.precision_score(y_test,y_pred))
+ recall = float(sm.recall_score(y_test,y_pred))
+ tn, fp, fn, tp = sm.confusion_matrix(y_test,y_pred).ravel()
+ specificity = float(tn / (tn+fp))
+ f1 = float(sm.f1_score(y_test,y_pred))
+ mse = float(sm.mean_squared_error(y_test,y_pred))
+ mae = float(sm.mean_absolute_error(y_test,y_pred))
+ mape = float(sm.mean_absolute_percentage_error(y_test,y_pred))
+ rmse = float(np.sqrt(sm.mean_squared_error(y_test,y_pred)))
+ fpr, tpr, _ = sm.roc_curve(y_test,y_pred)
+ # TODO upload trenirani model nazad na backend
+ return TrainingResult(accuracy, precision, recall, float(tn), float(fp), float(fn), float(tp), specificity, f1, mse, mae, mape, rmse, fpr.tolist(), tpr.tolist())
+
+
+
+
diff --git a/backend/microservice/ml_socket.py b/backend/microservice/api/ml_socket.py
index 5489b787..65dd7321 100644
--- a/backend/microservice/ml_socket.py
+++ b/backend/microservice/api/ml_socket.py
@@ -14,12 +14,15 @@ def get_or_create_eventloop():
# create handler for each connection
async def handler(websocket, path):
#data = json.loads(await websocket.recv())
- #reply = f"Data recieved as: {data}!"
#print(data['test'])
msg = await websocket.recv()
- await websocket.send("[" + msg + "]")
+ print(msg)
-start_server = websockets.serve(handler, "localhost", 5027)
+async def start():
+ start_server = websockets.serve(handler, "localhost", 5027)
+ print('Websocket starting...')
+ get_or_create_eventloop().run_until_complete(start_server)
+ get_or_create_eventloop().run_forever()
-get_or_create_eventloop().run_until_complete(start_server)
-get_or_create_eventloop().run_forever() \ No newline at end of file
+async def send(msg):
+ await websocket.send(msg) \ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 8c025c8b..3d909d7a 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -26,6 +26,7 @@
"bootstrap": "^5.1.3",
"chart.js": "^3.7.1",
"csv-parser": "^3.0.0",
+ "d3-graphviz": "^2.6.1",
"mdb-angular-ui-kit": "^2.0.0",
"ng-uikit-pro-standard": "^1.0.0",
"ng2-charts": "^3.0.8",
@@ -33,7 +34,7 @@
"ngx-cookie-service": "^13.1.2",
"ngx-csv-parser": "^0.0.7",
"rxjs": "~7.5.0",
- "tslib": "^2.3.0",
+ "tslib": "^2.3.1",
"websocket-ts": "^1.1.1",
"zone.js": "~0.11.4"
},
@@ -42,6 +43,7 @@
"@angular/cli": "~13.2.5",
"@angular/compiler-cli": "~13.2.0",
"@types/crypto-js": "^4.1.1",
+ "@types/d3-graphviz": "^2.6.7",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
@@ -2743,6 +2745,57 @@
"integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==",
"dev": true
},
+ "node_modules/@types/d3-color": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz",
+ "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==",
+ "dev": true
+ },
+ "node_modules/@types/d3-graphviz": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.7.tgz",
+ "integrity": "sha512-dKJjD5HiFvAmC0FL/c70VB1diie8FCpyiCZfxMlf6TwYBqUyFvS4XJt6MoxjIuQTJhKDBGzrIvDOgM8gYMLSVA==",
+ "dev": true,
+ "dependencies": {
+ "@types/d3-selection": "^1",
+ "@types/d3-transition": "^1",
+ "@types/d3-zoom": "^1"
+ }
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz",
+ "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==",
+ "dev": true,
+ "dependencies": {
+ "@types/d3-color": "^1"
+ }
+ },
+ "node_modules/@types/d3-selection": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.3.tgz",
+ "integrity": "sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==",
+ "dev": true
+ },
+ "node_modules/@types/d3-transition": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.3.2.tgz",
+ "integrity": "sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==",
+ "dev": true,
+ "dependencies": {
+ "@types/d3-selection": "^1"
+ }
+ },
+ "node_modules/@types/d3-zoom": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.8.3.tgz",
+ "integrity": "sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/d3-interpolate": "^1",
+ "@types/d3-selection": "^1"
+ }
+ },
"node_modules/@types/eslint": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
@@ -4565,6 +4618,99 @@
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
"dev": true
},
+ "node_modules/d3-color": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
+ "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
+ },
+ "node_modules/d3-dispatch": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
+ "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA=="
+ },
+ "node_modules/d3-drag": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz",
+ "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==",
+ "dependencies": {
+ "d3-dispatch": "1",
+ "d3-selection": "1"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
+ "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
+ },
+ "node_modules/d3-format": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
+ "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
+ },
+ "node_modules/d3-graphviz": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-2.6.1.tgz",
+ "integrity": "sha512-878AFSagQyr5tTOrM7YiVYeUC2/NoFcOB3/oew+LAML0xekyJSw9j3WOCUMBsc95KYe9XBYZ+SKKuObVya1tJQ==",
+ "dependencies": {
+ "d3-dispatch": "^1.0.3",
+ "d3-format": "^1.2.0",
+ "d3-interpolate": "^1.1.5",
+ "d3-path": "^1.0.5",
+ "d3-selection": "^1.1.0",
+ "d3-timer": "^1.0.6",
+ "d3-transition": "^1.1.1",
+ "d3-zoom": "^1.5.0",
+ "viz.js": "^1.8.2"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
+ "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
+ "dependencies": {
+ "d3-color": "1"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+ },
+ "node_modules/d3-selection": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
+ "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
+ },
+ "node_modules/d3-timer": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
+ "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
+ },
+ "node_modules/d3-transition": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz",
+ "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==",
+ "dependencies": {
+ "d3-color": "1",
+ "d3-dispatch": "1",
+ "d3-ease": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "^1.1.0",
+ "d3-timer": "1"
+ }
+ },
+ "node_modules/d3-zoom": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz",
+ "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==",
+ "dependencies": {
+ "d3-dispatch": "1",
+ "d3-drag": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "1",
+ "d3-transition": "1"
+ }
+ },
"node_modules/date-format": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz",
@@ -11042,6 +11188,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/viz.js": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.2.tgz",
+ "integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ==",
+ "deprecated": "no longer supported"
+ },
"node_modules/void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
@@ -13445,6 +13597,57 @@
"integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==",
"dev": true
},
+ "@types/d3-color": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz",
+ "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==",
+ "dev": true
+ },
+ "@types/d3-graphviz": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.7.tgz",
+ "integrity": "sha512-dKJjD5HiFvAmC0FL/c70VB1diie8FCpyiCZfxMlf6TwYBqUyFvS4XJt6MoxjIuQTJhKDBGzrIvDOgM8gYMLSVA==",
+ "dev": true,
+ "requires": {
+ "@types/d3-selection": "^1",
+ "@types/d3-transition": "^1",
+ "@types/d3-zoom": "^1"
+ }
+ },
+ "@types/d3-interpolate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz",
+ "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==",
+ "dev": true,
+ "requires": {
+ "@types/d3-color": "^1"
+ }
+ },
+ "@types/d3-selection": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.3.tgz",
+ "integrity": "sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA==",
+ "dev": true
+ },
+ "@types/d3-transition": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.3.2.tgz",
+ "integrity": "sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg==",
+ "dev": true,
+ "requires": {
+ "@types/d3-selection": "^1"
+ }
+ },
+ "@types/d3-zoom": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.8.3.tgz",
+ "integrity": "sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q==",
+ "dev": true,
+ "requires": {
+ "@types/d3-interpolate": "^1",
+ "@types/d3-selection": "^1"
+ }
+ },
"@types/eslint": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
@@ -14874,6 +15077,99 @@
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
"dev": true
},
+ "d3-color": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
+ "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
+ },
+ "d3-dispatch": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
+ "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA=="
+ },
+ "d3-drag": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz",
+ "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==",
+ "requires": {
+ "d3-dispatch": "1",
+ "d3-selection": "1"
+ }
+ },
+ "d3-ease": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
+ "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
+ },
+ "d3-format": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
+ "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
+ },
+ "d3-graphviz": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-2.6.1.tgz",
+ "integrity": "sha512-878AFSagQyr5tTOrM7YiVYeUC2/NoFcOB3/oew+LAML0xekyJSw9j3WOCUMBsc95KYe9XBYZ+SKKuObVya1tJQ==",
+ "requires": {
+ "d3-dispatch": "^1.0.3",
+ "d3-format": "^1.2.0",
+ "d3-interpolate": "^1.1.5",
+ "d3-path": "^1.0.5",
+ "d3-selection": "^1.1.0",
+ "d3-timer": "^1.0.6",
+ "d3-transition": "^1.1.1",
+ "d3-zoom": "^1.5.0",
+ "viz.js": "^1.8.2"
+ }
+ },
+ "d3-interpolate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
+ "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
+ "requires": {
+ "d3-color": "1"
+ }
+ },
+ "d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+ },
+ "d3-selection": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
+ "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
+ },
+ "d3-timer": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
+ "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
+ },
+ "d3-transition": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz",
+ "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==",
+ "requires": {
+ "d3-color": "1",
+ "d3-dispatch": "1",
+ "d3-ease": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "^1.1.0",
+ "d3-timer": "1"
+ }
+ },
+ "d3-zoom": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz",
+ "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==",
+ "requires": {
+ "d3-dispatch": "1",
+ "d3-drag": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "1",
+ "d3-transition": "1"
+ }
+ },
"date-format": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.4.tgz",
@@ -19594,6 +19890,11 @@
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
"dev": true
},
+ "viz.js": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.2.tgz",
+ "integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ=="
+ },
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 8cd6db58..975c740f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -28,6 +28,7 @@
"bootstrap": "^5.1.3",
"chart.js": "^3.7.1",
"csv-parser": "^3.0.0",
+ "d3-graphviz": "^2.6.1",
"mdb-angular-ui-kit": "^2.0.0",
"ng-uikit-pro-standard": "^1.0.0",
"ng2-charts": "^3.0.8",
@@ -35,7 +36,7 @@
"ngx-cookie-service": "^13.1.2",
"ngx-csv-parser": "^0.0.7",
"rxjs": "~7.5.0",
- "tslib": "^2.3.0",
+ "tslib": "^2.3.1",
"websocket-ts": "^1.1.1",
"zone.js": "~0.11.4"
},
@@ -44,6 +45,7 @@
"@angular/cli": "~13.2.5",
"@angular/compiler-cli": "~13.2.0",
"@types/crypto-js": "^4.1.1",
+ "@types/d3-graphviz": "^2.6.7",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts
index f6e01d08..32247bbd 100644
--- a/frontend/src/app/_data/Model.ts
+++ b/frontend/src/app/_data/Model.ts
@@ -15,7 +15,7 @@ export default class Model {
public randomTestSetDistribution: number = 0.1, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U
// Neural net training settings
- public type: ANNType = ANNType.FullyConnected,
+ public type: ProblemType = ProblemType.Regression,
public encoding: Encoding = Encoding.Label,
public optimizer: Optimizer = Optimizer.Adam,
public lossFunction: LossFunction = LossFunction.MeanSquaredError,
@@ -23,18 +23,21 @@ export default class Model {
public hiddenLayerNeurons: number = 1,
public hiddenLayers: number = 1,
public batchSize: number = 5,
- public inputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
- public hiddenLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
+ public hiddenLayerActivationFunctions: string[] = ['sigmoid'],
+ //public inputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
public username: string = '',
public nullValues: NullValueOptions = NullValueOptions.DeleteRows,
- public nullValuesReplacers = []
+ public nullValuesReplacers = [],
+ public metrics: Metric[] = [], // TODO add to add-model form
+ public epochs: number = 5 // TODO add to add-model form
) { }
}
-export enum ANNType {
- FullyConnected = 'potpuno povezana',
- Convolutional = 'konvoluciona'
+export enum ProblemType {
+ Regression = 'regresioni',
+ BinaryClassification = 'binarni-klasifikacioni',
+ MultiClassification = 'multi-klasifikacioni'
}
// replaceMissing srednja vrednost mean, median, najcesca vrednost (mode)
@@ -110,4 +113,11 @@ export enum ReplaceWith {
None = 'Popuni...',
Mean = 'Srednja vrednost',
Median = 'Medijana'
+}
+
+export enum Metric {
+ MSE = 'mse',
+ MAE = 'mae',
+ RMSE = 'rmse'
+ //...
} \ No newline at end of file
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.css b/frontend/src/app/_elements/annvisual/annvisual.component.css
new file mode 100644
index 00000000..857a3390
--- /dev/null
+++ b/frontend/src/app/_elements/annvisual/annvisual.component.css
@@ -0,0 +1,4 @@
+#graph{
+ width: 100%;
+ text-align: center;
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.html b/frontend/src/app/_elements/annvisual/annvisual.component.html
new file mode 100644
index 00000000..f23022de
--- /dev/null
+++ b/frontend/src/app/_elements/annvisual/annvisual.component.html
@@ -0,0 +1,5 @@
+<div style="text-align: center; width: 100%;" >
+ <button (click)="d3()" mat-raised-button color="primary">Prikaz veštačke neuronske mreže</button>
+ <div id="graph" align-items-center ></div>
+ </div>
+
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.spec.ts b/frontend/src/app/_elements/annvisual/annvisual.component.spec.ts
new file mode 100644
index 00000000..cb07ef1d
--- /dev/null
+++ b/frontend/src/app/_elements/annvisual/annvisual.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AnnvisualComponent } from './annvisual.component';
+
+describe('AnnvisualComponent', () => {
+ let component: AnnvisualComponent;
+ let fixture: ComponentFixture<AnnvisualComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ AnnvisualComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AnnvisualComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.ts b/frontend/src/app/_elements/annvisual/annvisual.component.ts
new file mode 100644
index 00000000..ff5b45d6
--- /dev/null
+++ b/frontend/src/app/_elements/annvisual/annvisual.component.ts
@@ -0,0 +1,47 @@
+import { Component, OnInit,Input } from '@angular/core';
+import Model from 'src/app/_data/Model';
+import { graphviz } from 'd3-graphviz';
+
+@Component({
+ selector: 'app-annvisual',
+ templateUrl: './annvisual.component.html',
+ styleUrls: ['./annvisual.component.css']
+})
+export class AnnvisualComponent implements OnInit {
+ ngOnInit(): void {
+ throw new Error('Method not implemented.');
+ }
+
+ @Input() model: Model = new Model();
+
+ d3(){
+ let inputlayerstring:string='';
+ let hiddenlayerstring:string='';
+ let digraphstring:string='digraph {';
+
+ for(let i=0;i<this.model.inputNeurons;i++)
+ {
+ inputlayerstring=inputlayerstring+'i'+i+',';
+ }
+ inputlayerstring=inputlayerstring.slice(0,-1);
+
+ digraphstring=digraphstring+'->';
+
+ for(let j=0;j<this.model.hiddenLayers;j++)
+ {
+ for(let i=0;i<this.model.hiddenLayerNeurons;i++)
+ {
+ hiddenlayerstring=hiddenlayerstring+'h'+j+'_'+i+',';
+ }
+ hiddenlayerstring=hiddenlayerstring.slice(0,1);
+ digraphstring=digraphstring+hiddenlayerstring+'->';
+ hiddenlayerstring='';
+ }
+ digraphstring=digraphstring+'o}';
+ alert(digraphstring);
+
+ graphviz('#graph').renderDot(digraphstring);
+ }
+
+
+}
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.html b/frontend/src/app/_elements/item-predictor/item-predictor.component.html
index 92d747e2..b4690154 100644
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.html
+++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.html
@@ -19,6 +19,6 @@
</div>
</div>
<div class="card-footer text-center">
- <a routerLink="predict" mat-raised-button color="primary">Iskoristi</a>
+ <a routerLink="/predict" mat-raised-button color="primary">Iskoristi</a>
</div>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.css b/frontend/src/app/_elements/reactive-background/reactive-background.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.css
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.html b/frontend/src/app/_elements/reactive-background/reactive-background.component.html
new file mode 100644
index 00000000..756952fb
--- /dev/null
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.html
@@ -0,0 +1 @@
+<canvas id="bgCanvas" width="200" height="200" style="position: fixed; z-index: -1;"></canvas> \ No newline at end of file
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.spec.ts b/frontend/src/app/_elements/reactive-background/reactive-background.component.spec.ts
new file mode 100644
index 00000000..441f4b11
--- /dev/null
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ReactiveBackgroundComponent } from './reactive-background.component';
+
+describe('ReactiveBackgroundComponent', () => {
+ let component: ReactiveBackgroundComponent;
+ let fixture: ComponentFixture<ReactiveBackgroundComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ReactiveBackgroundComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ReactiveBackgroundComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.ts b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts
new file mode 100644
index 00000000..8294a8a5
--- /dev/null
+++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts
@@ -0,0 +1,167 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-reactive-background',
+ templateUrl: './reactive-background.component.html',
+ styleUrls: ['./reactive-background.component.css']
+})
+export class ReactiveBackgroundComponent implements OnInit {
+
+ numPoints: number = 450;
+ speed: number = 0.001; // 0-1
+ rotateInterval: number = 1000;
+ maxSize: number = 6;
+
+ minDistance: number = 0.07; //0-1
+ cursorDistance: number = 0.07;
+
+ private points: Point[] = [];
+
+ private width = 200;
+ private height = 200;
+ private ratio = 1;
+
+ private canvas?: HTMLCanvasElement;
+ private ctx?: CanvasRenderingContext2D;
+
+ private time: number = 0;
+
+ constructor() { }
+
+ private mouseX = 0;
+ private mouseY = 0;
+
+ ngOnInit(): void {
+
+ document.addEventListener('mousemove', (e) => {
+ this.mouseX = e.clientX / this.width;
+ this.mouseY = e.clientY / this.height;
+ })
+
+ this.canvas = (<HTMLCanvasElement>document.getElementById('bgCanvas'));
+ const ctx = this.canvas.getContext('2d');
+ if (ctx) {
+ this.ctx = ctx;
+ } else {
+ console.warn('Could not get canvas context!');
+ }
+
+ let i = 0;
+ while (i < this.numPoints) {
+ const x = Math.random();
+ const y = Math.random();
+ const size = (Math.random() * 0.8 + 0.2) * this.maxSize;
+ const direction = Math.random() * 360;
+ this.points.push(new Point(x, y, size, direction));
+ i++;
+ }
+
+ window.addEventListener('resize', () => { this.resize() });
+ this.resize();
+
+ setInterval(() => {
+ this.drawBackground();
+ }, 1000 / 60);
+ }
+
+ drawBackground() {
+ if (!this.ctx || !this.canvas) return;
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ this.ctx.fillStyle = "#222277";
+ this.ctx.fillRect(0, 0, this.width, this.height);
+
+ this.points.forEach((point, index) => {
+ this.drawLines(point, index);
+ this.drawPoint(point);
+ this.updatePoint(point);
+ });
+
+ //this.drawPoint(new Point(this.mouseX, this.mouseY, 12, 0));
+
+ this.time += 1;
+ }
+
+ drawLines(p: Point, index: number) {
+ let i = index + 1;
+ while (i < this.points.length) {
+ const otherPoint = this.points[i];
+
+ const dist = this.distance(p.x, p.y, otherPoint.x, otherPoint.y);
+ if (dist < this.minDistance) {
+ const h = HEX[Math.round((1 - dist / this.minDistance) * 16)]
+ this.ctx!.strokeStyle = '#ffffff' + h + h;
+ this.ctx!.beginPath();
+ this.ctx!.moveTo(p.x * this.width, p.y * this.height);
+ this.ctx!.lineTo(otherPoint.x * this.width, otherPoint.y * this.height);
+ this.ctx!.stroke();
+ }
+
+ i++;
+ }
+ }
+
+ drawPoint(p: Point) {
+ this.ctx!.fillStyle = '#ffffff';
+ this.ctx!.beginPath();
+ this.ctx!.arc(p.x * this.width, p.y * this.height, p.size, 0, 2 * Math.PI);
+ this.ctx!.fill();
+ }
+
+ resize() {
+ this.width = window.innerWidth;
+ this.height = window.innerHeight;
+ this.ratio = this.width / this.height;
+
+ if (this.canvas) {
+ this.canvas.width = this.width;
+ this.canvas.height = this.height;
+ }
+
+ this.drawBackground();
+ }
+
+ updatePoint(p: Point) {
+ const vx = Math.sin(p.direction);
+ const vy = Math.cos(p.direction);
+
+ p.x = p.x + vx * this.speed;
+ p.y = p.y + vy * this.speed;
+
+ const mx = this.mouseX;
+ const my = this.mouseY;
+ const distToCursor = this.distance(p.x, p.y, mx, my);
+ if (distToCursor < this.cursorDistance) {
+
+ p.x -= ((mx - p.x) / distToCursor) / 500;
+ p.y -= ((my - p.y) / distToCursor) / 500;
+
+ const grd = this.ctx!.createLinearGradient(p.x * this.width, p.y * this.height, mx * this.width, my * this.height);
+ grd.addColorStop(0, '#ff0000ff');
+ grd.addColorStop(1, '#ff000000');
+ this.ctx!.strokeStyle = grd;
+ this.ctx!.beginPath();
+ this.ctx!.moveTo(p.x * this.width, p.y * this.height);
+ this.ctx!.lineTo(mx * this.width, my * this.height);
+ this.ctx!.stroke();
+ }
+
+ p.x %= 1;
+ p.y %= 1;
+ }
+
+ distance(x1: number, y1: number, x2: number, y2: number): number {
+ return Math.sqrt(((x2 - x1) ** 2) + ((y2 / this.ratio - y1 / this.ratio) ** 2));
+ }
+}
+
+class Point {
+ constructor(
+ public x: number,
+ public y: number,
+ public size: number,
+ public direction: number
+ ) { }
+}
+
+const HEX = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; \ No newline at end of file
diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html
index 09a11e37..662d34de 100644
--- a/frontend/src/app/_pages/add-model/add-model.component.html
+++ b/frontend/src/app/_pages/add-model/add-model.component.html
@@ -40,21 +40,23 @@
Dodajte novi dataset
</button>
</div>
-
+ <div class="px-5 my-2">
+ <input *ngIf="showMyDatasets" type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term">
+ </div>
<div class="px-5">
<div *ngIf="showMyDatasets" class="overflow-auto" style="max-height: 500px;">
<ul class="list-group">
- <li class="list-group-item p-3" *ngFor="let dataset of myDatasets"
+ <li class="list-group-item p-3" *ngFor="let dataset of myDatasets|filter:term"
[ngClass]="{'selectedDatasetClass': this.selectedDataset == dataset}">
<app-item-dataset name="usersDataset" [dataset]="dataset"
- (click)="selectThisDataset(dataset)"></app-item-dataset>
+ (click)="scrollToNextForm(); selectThisDataset(dataset);"></app-item-dataset>
</li>
</ul>
</div>
</div>
<app-dataset-load *ngIf="!showMyDatasets" id="dataset"
- (loaded)="datasetLoaded = true; selectedDataset = datasetLoadComponent?.dataset; datasetFile = datasetLoadComponent?.csvRecords; datasetHasHeader = datasetLoadComponent?.dataset!.hasHeader">
+ (loaded)="scrollToNextForm(); datasetLoaded = true; selectedDataset = datasetLoadComponent?.dataset; datasetFile = datasetLoadComponent?.csvRecords; datasetHasHeader = datasetLoadComponent?.dataset!.hasHeader">
</app-dataset-load>
<div class="px-5 mt-5">
<app-datatable [data]="datasetFile" [hasHeader]="datasetHasHeader"></app-datatable>
@@ -62,6 +64,7 @@
</div>
<!-- ULAZNE/IZLAZNE KOLONE -->
+ <span id="selectInAndOuts"></span>
<div *ngIf="selectedDataset">
<div class="row">
<div class="col d-flex justify-content-center">
@@ -70,7 +73,8 @@
<br>
<div *ngFor="let item of selectedDataset.header; let i = index">
<input class="form-check-input" type="checkbox" value="{{item}}" id="cb_{{item}}"
- name="cbsNew" checked [disabled]="this.selectedOutputColumnVal == item">&nbsp;
+ name="cbsNew" [checked]="this.selectedOutputColumnVal != item"
+ [disabled]="this.selectedOutputColumnVal == item">&nbsp;
<label class="form-check-label" for="cb_{{item}}">
{{item}}
</label>
@@ -92,7 +96,7 @@
</div>
- <div class="my-2" *ngIf="datasetFile">
+ <div class="mt-5" *ngIf="datasetFile">
<h2>Popunjavanje nedostajućih vrednosti:</h2>
<div class="form-check">
<input type="radio" [(ngModel)]="newModel.nullValues" [value]="NullValueOptions.DeleteRows"
@@ -151,8 +155,6 @@
</div>
</div>
-
-
<h2 class="mt-5 mb-4">Parametri treniranja:</h2>
<div>
@@ -160,11 +162,12 @@
<div class="col-1">
</div>
<div class="col-3">
- <label for="type" class="col-form-label">Tip mreže: </label>
+ <label for="type" class="col-form-label">Tip problema: </label>
</div>
<div class="col-2">
<select id=typeOptions class="form-control" name="type" [(ngModel)]="newModel.type">
- <option *ngFor="let option of Object.keys(ANNType); let optionName of Object.values(ANNType)"
+ <option
+ *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)"
[value]="option">
{{ optionName }}
</option>
@@ -177,7 +180,8 @@
</div>
<div class="col-1">
<input type="number" min="1" class="form-control" name="hiddenLayers"
- [(ngModel)]="newModel.hiddenLayers">
+ [(ngModel)]="newModel.hiddenLayers"
+ (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])">
</div>
</div>
@@ -259,52 +263,36 @@
</div>
<div class="row p-2">
- <div class="col-1">
- </div>
+ <div class="col-3"></div>
<div class="col-3">
- <label for="inputLayerActivationFunction" class="col-form-label">Funkcija aktivacije ulaznog
- sloja:</label>
+ <label for="hiddenLayerActivationFunction" class="col-form-label">Funkcija aktivacije skrivenih
+ slojeva:</label>
</div>
- <div class="col-2">
- <select id=inputLayerActivationFunctionOptions class="form-control"
- name="inputLayerActivationFunction" [(ngModel)]="newModel.inputLayerActivationFunction">
- <option
- *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
+ <div class="col-3">
+ <div *ngFor="let item of [].constructor(newModel.hiddenLayers); let i = index">
+ <select [id]="'hiddenLayerActivationFunctionOption_'+i" class="form-control"
+ [(ngModel)]="newModel.hiddenLayerActivationFunctions[i]">
+ <option
+ *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
</div>
+ <div class="col-3"></div>
+ </div>
+
+ <div class="row p-2">
<div class="col-1">
</div>
- <div class="col-5">
+ <div class="col-3">
<label for="splitYesNo" class="form-check-label">Podela test skupa:&nbsp;&nbsp;
<input id="splitYesNo" class="form-check-input" type="checkbox"
[checked]="newModel.randomTestSet"
(change)="newModel.randomTestSet = !newModel.randomTestSet">
</label>
</div>
- <div class="col">
- </div>
- </div>
-
- <div class="row p-2">
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="hiddenLayerActivationFunction" class="col-form-label">Funkcija aktivacije skrivenih
- slojeva:</label>
- </div>
- <div class="col-2">
- <select id=hiddenLayerActivationFunctionOptions class="form-control"
- name="hiddenLayerActivationFunction" [(ngModel)]="newModel.hiddenLayerActivationFunction">
- <option
- *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
<div class="col-1">
</div>
<div class="col-2">
@@ -354,7 +342,7 @@
<button class="btn btn-lg col-4" style="background-color:#003459; color:white;"
(click)="addModel();">Sačuvaj model</button>
<div class="col"></div>
- <button class="btn btn-lg col-4 disabled" style="background-color:#003459; color:white;"
+ <button class="btn btn-lg col-4" style="background-color:#003459; color:white;"
(click)="trainModel();">Treniraj model</button>
<div class="col"></div>
</div>
diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts
index 995aaa87..77a506d5 100644
--- a/frontend/src/app/_pages/add-model/add-model.component.ts
+++ b/frontend/src/app/_pages/add-model/add-model.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import Model, { ReplaceWith } from 'src/app/_data/Model';
-import { ANNType, Encoding, ActivationFunction, LossFunction, Optimizer, NullValueOptions } from 'src/app/_data/Model';
+import { ProblemType, Encoding, ActivationFunction, LossFunction, Optimizer, NullValueOptions } from 'src/app/_data/Model';
import { DatasetLoadComponent } from 'src/app/_elements/dataset-load/dataset-load.component';
import { ModelsService } from 'src/app/_services/models.service';
import shared from 'src/app/Shared';
@@ -23,7 +23,7 @@ export class AddModelComponent implements OnInit {
newModel: Model;
- ANNType = ANNType;
+ ProblemType = ProblemType;
Encoding = Encoding;
ActivationFunction = ActivationFunction;
LossFunction = LossFunction;
@@ -47,10 +47,13 @@ export class AddModelComponent implements OnInit {
tempTestSetDistribution: number = 90;
+ //accepted: Boolean;
+ term: string = "";
+
constructor(private models: ModelsService, private datasets: DatasetsService, private csv: CsvParseService) {
this.newModel = new Model();
- this.models.getMyDatasets().subscribe((datasets) => {
+ this.datasets.getMyDatasets().subscribe((datasets) => {
this.myDatasets = datasets;
});
}
@@ -73,19 +76,28 @@ export class AddModelComponent implements OnInit {
addModel() {
if (!this.showMyDatasets)
- this.saveModelWithNewDataset();
+ this.saveModelWithNewDataset(_ => { console.log('MODEL ADDED (with new dataset).') });
else
- this.saveModelWithExistingDataset();
+ this.saveModelWithExistingDataset(_ => { console.log('MODEL ADDED (with existing dataset).') });
}
trainModel() {
- this.saveModelWithNewDataset().subscribe((modelId: any) => {
- if (modelId)
- this.models.trainModel(modelId);
- }); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad
+ let saveFunc;
+
+ if (!this.showMyDatasets)
+ saveFunc = (x: (arg0: any) => void) => { this.saveModelWithNewDataset(x) };
+ else
+ saveFunc = (x: (arg0: any) => void) => { this.saveModelWithExistingDataset(x) };
+
+ saveFunc(((model: any) => {
+ console.log('Saved, training model...', model);
+ this.models.trainModel(model).subscribe(response => {
+ console.log('Train model complete!', response);
+ });
+ })); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad
}
- saveModelWithNewDataset(): any {
+ saveModelWithNewDataset(callback: ((arg0: any) => void)) {
this.getCheckedInputCols();
this.getCheckedOutputCol();
@@ -93,14 +105,14 @@ export class AddModelComponent implements OnInit {
if (this.validationInputsOutput()) {
console.log('ADD MODEL: STEP 1 - UPLOAD FILE');
if (this.datasetLoadComponent) {
-
+ console.log("this.datasetLoadComponent.files:", this.datasetLoadComponent.files);
this.models.uploadData(this.datasetLoadComponent.files[0]).subscribe((file) => {
console.log('ADD MODEL: STEP 2 - ADD DATASET WITH FILE ID ' + file._id);
if (this.datasetLoadComponent) {
this.datasetLoadComponent.dataset.fileId = file._id;
this.datasetLoadComponent.dataset.username = shared.username;
- this.models.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => {
+ this.datasets.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => {
console.log('ADD MODEL: STEP 3 - ADD MODEL WITH DATASET ID ', dataset._id);
this.newModel.datasetId = dataset._id;
@@ -114,7 +126,7 @@ export class AddModelComponent implements OnInit {
this.newModel.username = shared.username;
this.models.addModel(this.newModel).subscribe((response) => {
- console.log('ADD MODEL: DONE! REPLY:\n', response);
+ callback(response);
}, (error) => {
alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom.");
}); //kraj addModel subscribe
@@ -130,8 +142,7 @@ export class AddModelComponent implements OnInit {
} //kraj prvog ifa
}
- saveModelWithExistingDataset(): any {
-
+ saveModelWithExistingDataset(callback: ((arg0: any) => void)): any {
if (this.selectedDataset) { //dataset je izabran
this.getCheckedInputCols();
this.getCheckedOutputCol();
@@ -144,7 +155,7 @@ export class AddModelComponent implements OnInit {
this.newModel.username = shared.username;
this.models.addModel(this.newModel).subscribe((response) => {
- console.log('ADD MODEL: DONE! REPLY:\n', response);
+ callback(response);
}, (error) => {
alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom.");
});
@@ -216,12 +227,16 @@ export class AddModelComponent implements OnInit {
if (datasets[i]._id == dataset._id)
}*/
-
//this.datasetFile = csvRecords;
this.datasets.getDatasetFile(dataset.fileId).subscribe((file: string | undefined) => {
if (file) {
this.datasetFile = this.csv.csvToArray(file, (dataset.delimiter == "razmak") ? " " : (dataset.delimiter == "") ? "," : dataset.delimiter);
- this.datasetFile.length = this.datasetFile.length - 1;
+ for (let i = this.datasetFile.length - 1; i >= 0; i--) { //moguce da je vise redova na kraju fajla prazno i sl.
+ if (this.datasetFile[i].length != this.datasetFile[0].length)
+ this.datasetFile[i].pop();
+ else
+ break; //nema potrebe dalje
+ }
console.log(this.datasetFile);
}
});
@@ -230,6 +245,15 @@ export class AddModelComponent implements OnInit {
this.resetCbsAndRbs();
}
+ scrollToNextForm() {
+ console.log("USAO U SCROLL");
+ (<HTMLSelectElement>document.getElementById("selectInAndOuts")).scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ inline: "nearest"
+ });
+ }
+
resetSelectedDataset(): boolean {
const temp = this.selectedDataset;
this.selectedDataset = this.otherDataset;
@@ -263,7 +287,7 @@ export class AddModelComponent implements OnInit {
}
refreshMyDatasetList() {
- this.models.getMyDatasets().subscribe((datasets) => {
+ this.datasets.getMyDatasets().subscribe((datasets) => {
this.myDatasets = datasets;
});
}
diff --git a/frontend/src/app/_pages/home/home.component.html b/frontend/src/app/_pages/home/home.component.html
index 7e895a2d..eb59b726 100644
--- a/frontend/src/app/_pages/home/home.component.html
+++ b/frontend/src/app/_pages/home/home.component.html
@@ -45,12 +45,12 @@
</div>
<h2 class="my-4">Pogledajte javne izvore podataka!</h2>
- <app-carousel [items]="publicDatasets">
+ <app-carousel *ngIf = "publicDatasets" [items]="publicDatasets">
</app-carousel>
<h3><a routerLink="browse-datasets">Pogledaj sve javne izvore podataka...</a></h3>
<h2 class="my-4">Iskoristite već trenirane modele!</h2>
- <app-carousel [items]="publicPredictors">
+ <app-carousel *ngIf = "publicPredictors" [items]="publicPredictors">
</app-carousel>
<h3><a routerLink="browse-predictors">Pogledaj sve javne trenirane modele...</a></h3>
</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/home/home.component.ts b/frontend/src/app/_pages/home/home.component.ts
index 7e4471e8..ed86a329 100644
--- a/frontend/src/app/_pages/home/home.component.ts
+++ b/frontend/src/app/_pages/home/home.component.ts
@@ -3,6 +3,8 @@ import Dataset from 'src/app/_data/Dataset';
import Predictor from 'src/app/_data/Predictor';
import { ItemDatasetComponent } from 'src/app/_elements/item-dataset/item-dataset.component';
import shared from 'src/app/Shared';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+import { PredictorsService } from 'src/app/_services/predictors.service';
@Component({
selector: 'app-home',
@@ -11,32 +13,19 @@ import shared from 'src/app/Shared';
})
export class HomeComponent implements OnInit {
- publicDatasets: Dataset[];
- publicPredictors: Predictor[];
+ publicDatasets?: Dataset[];
+ publicPredictors?: Predictor[];
shared = shared;
- constructor() {
- this.publicDatasets = [
- new Dataset('Titanik', 'Titanik', ['Kolona1', 'Kolona2', 'Ime', 'OsobaJePreživela']),
- new Dataset('Drugi Dataset', 'Lorem ipsum dolor sir amet', ['jabuka', 'kruska', 'jagoda']),
- new Dataset('Dataset III', 'Kratak opis izvora podataka', ['c1', 'c2', 'c3', 'c4', 'c5']),
- new Dataset('Drugi Dataset', 'Lorem ipsum dolor sir amet', ['jabuka', 'kruska', 'jagoda']),
- new Dataset('Dataset III', 'Kratak opis izvora podataka', ['c1', 'c2', 'c3', 'c4', 'c5']),
- new Dataset('Drugi Dataset', 'Lorem ipsum dolor sir amet', ['jabuka', 'kruska', 'jagoda']),
- new Dataset('Dataset III', 'Kratak opis izvora podataka', ['c1', 'c2', 'c3', 'c4', 'c5']),
- new Dataset('Dataset III', 'Kratak opis izvora podataka', ['c1', 'c2', 'c3', 'c4', 'c5'])
- ]
- this.publicPredictors = [
- new Predictor('Preživeli', 'Za uneto ime osobe, predvidja da li je ta osoba preživela ili ne.', ['Ime'], 'OsobaJePreživela'),
- new Predictor('Drugi model', 'Lorem ipsum dolor sir amet', ['kruska'], 'jagoda'),
- new Predictor('Treći model', 'Kratak opis modela', ['c1', 'c2', 'c3'], 'c5'),
- new Predictor('Drugi model', 'Lorem ipsum dolor sir amet', ['kruska'], 'jagoda'),
- new Predictor('Treći model', 'Kratak opis modela', ['c1', 'c2', 'c3'], 'c5'),
- new Predictor('Drugi model', 'Lorem ipsum dolor sir amet', ['kruska'], 'jagoda'),
- new Predictor('Treći model', 'Kratak opis modela', ['c1', 'c2', 'c3'], 'c5'),
- new Predictor('Treći model', 'Kratak opis modela', ['c1', 'c2', 'c3'], 'c5')
- ]
+ constructor(private datasetsService: DatasetsService, private predictorsService: PredictorsService) {
+ this.datasetsService.getPublicDatasets().subscribe((datasets) => {
+ this.publicDatasets = datasets;
+ console.log(datasets);
+ });
+ this.predictorsService.getPublicPredictors().subscribe((predictors) => {
+ this.publicPredictors = predictors;
+ });
}
ngOnInit(): void {
diff --git a/frontend/src/app/_pages/my-models/my-models.component.html b/frontend/src/app/_pages/my-models/my-models.component.html
index 870e0ddb..b6926771 100644
--- a/frontend/src/app/_pages/my-models/my-models.component.html
+++ b/frontend/src/app/_pages/my-models/my-models.component.html
@@ -9,7 +9,9 @@
<div class="col-sm-4" style="margin-bottom: 10px;" *ngFor="let model of myModels">
<app-item-model [model]="model"></app-item-model>
<div style="width: 25%; margin: auto;">
- <button (click)="deleteThisModel(model)" style="margin-top: 3px; width: 100%;">Obriši</button>
+ <button mat-raised-button color="primary" (click)="deleteThisModel(model)" style="margin-top: 3px; width: 100%;">Obriši</button>
+
+ <button mat-raised-button color="primary" (click)="deleteThisModel(model)" style="margin-top: 3px; width: 100%;">Koristi</button>
</div>
</div>
</div>
diff --git a/frontend/src/app/_services/datasets.service.ts b/frontend/src/app/_services/datasets.service.ts
index 35ca24e5..0ff63828 100644
--- a/frontend/src/app/_services/datasets.service.ts
+++ b/frontend/src/app/_services/datasets.service.ts
@@ -16,7 +16,11 @@ export class DatasetsService {
return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/publicdatasets`, { headers: this.authService.authHeader() });
}
- addDataset(dataset: Dataset): any {
+ getMyDatasets(): Observable<Dataset[]> {
+ return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() });
+ }
+
+ addDataset(dataset: Dataset): Observable<any> {
return this.http.post(`${API_SETTINGS.apiURL}/dataset/add`, dataset, { headers: this.authService.authHeader() });
}
diff --git a/frontend/src/app/_services/home.service.spec.ts b/frontend/src/app/_services/home.service.spec.ts
new file mode 100644
index 00000000..1afaf229
--- /dev/null
+++ b/frontend/src/app/_services/home.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { HomeService } from './home.service';
+
+describe('HomeService', () => {
+ let service: HomeService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(HomeService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_services/home.service.ts b/frontend/src/app/_services/home.service.ts
new file mode 100644
index 00000000..0026413a
--- /dev/null
+++ b/frontend/src/app/_services/home.service.ts
@@ -0,0 +1,9 @@
+import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class HomeService {
+
+ constructor() { }
+}
diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts
index 58ddb2e6..3fbad109 100644
--- a/frontend/src/app/_services/models.service.ts
+++ b/frontend/src/app/_services/models.service.ts
@@ -1,10 +1,10 @@
-import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http';
+import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import Model from '../_data/Model';
import { AuthService } from './auth.service';
import { API_SETTINGS } from 'src/config';
-import Dataset from '../_data/Dataset';
import { Observable } from 'rxjs';
+import Dataset from '../_data/Dataset';
@Injectable({
@@ -35,25 +35,23 @@ export class ModelsService {
addDataset(dataset: Dataset): Observable<any> {
return this.http.post(`${API_SETTINGS.apiURL}/dataset/add`, dataset, { headers: this.authService.authHeader() });
}
- trainModel(modelId: string): Observable<any> {
- return this.http.post(`${API_SETTINGS.apiURL}/model/train`, modelId, { headers: this.authService.authHeader() });
+ trainModel(model: Model): Observable<any> {
+ return this.http.post(`${API_SETTINGS.apiURL}/model/sendmodel`, model, { headers: this.authService.authHeader(), responseType: 'text' });
}
getMyDatasets(): Observable<Dataset[]> {
return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() });
}
-
+
getMyModels(): Observable<Model[]> {
return this.http.get<Model[]>(`${API_SETTINGS.apiURL}/model/mymodels`, { headers: this.authService.authHeader() });
}
- editModel(model:Model) : Observable<Model>
- {
+ editModel(model: Model): Observable<Model> {
return this.http.put<Model>(`${API_SETTINGS.apiURL}/model/`, model, { headers: this.authService.authHeader() });
}
- deleteModel(model:Model) : Observable<any>
- {
- return this.http.delete(`${API_SETTINGS.apiURL}/model/`+model.name, { headers: this.authService.authHeader() });
+ deleteModel(model: Model) {
+ return this.http.delete(`${API_SETTINGS.apiURL}/model/` + model.name, { headers: this.authService.authHeader(), responseType: "text" });
}
}
diff --git a/frontend/src/app/_services/predictors.service.ts b/frontend/src/app/_services/predictors.service.ts
index 0cd7f0f6..a2dc012f 100644
--- a/frontend/src/app/_services/predictors.service.ts
+++ b/frontend/src/app/_services/predictors.service.ts
@@ -15,7 +15,7 @@ export class PredictorsService {
constructor(private http: HttpClient, private authService: AuthService) { }
getPublicPredictors(): Observable<Predictor[]> {
- return this.http.get<Predictor[]>(`${API_SETTINGS.apiURL}/Predictor/publicpredictors`, { headers: this.authService.authHeader() });
+ return this.http.get<Predictor[]>(`${API_SETTINGS.apiURL}/predictor/publicpredictors`, { headers: this.authService.authHeader() });
}
}
diff --git a/frontend/src/app/_services/web-socket.service.ts b/frontend/src/app/_services/web-socket.service.ts
index 890ada6b..1a7efa87 100644
--- a/frontend/src/app/_services/web-socket.service.ts
+++ b/frontend/src/app/_services/web-socket.service.ts
@@ -13,15 +13,15 @@ export class WebSocketService {
constructor() {
this.ws = new WebsocketBuilder(API_SETTINGS.apiWSUrl)
- .withBackoff(new ConstantBackoff(30000))
- .onOpen((i, e) => { console.log('WS: Connected to ' + API_SETTINGS.apiWSUrl) })
+ .withBackoff(new ConstantBackoff(120000))
+ .onOpen((i, e) => { /*console.log('WS: Connected to ' + API_SETTINGS.apiWSUrl)*/ })
.onMessage((i, e) => {
console.log('WS MESSAGE: ', e.data);
this.handlers.forEach(handler => {
handler(e.data);
})
})
- .onClose((i, e) => { console.log('WS: Connection closed!') })
+ .onClose((i, e) => { /*console.log('WS: Connection closed!')*/ })
.build();
}
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
index f44a6d00..f0e563f4 100644
--- a/frontend/src/app/app.component.html
+++ b/frontend/src/app/app.component.html
@@ -1,3 +1,4 @@
+<app-reactive-background></app-reactive-background>
<app-navbar></app-navbar>
<div class="container h-100">
<router-outlet></router-outlet>
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index 0531a958..5d7af9d2 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -36,6 +36,7 @@ import { BarchartComponent } from './barchart/barchart.component';
import { NotificationsComponent } from './_elements/notifications/notifications.component';
import { DatatableComponent } from './_elements/datatable/datatable.component';
import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-datasets.component';
+import { ReactiveBackgroundComponent } from './_elements/reactive-background/reactive-background.component';
import { ItemModelComponent } from './_elements/item-model/item-model.component';
@NgModule({
@@ -63,6 +64,7 @@ import { ItemModelComponent } from './_elements/item-model/item-model.component'
NotificationsComponent,
DatatableComponent,
FilterDatasetsComponent,
+ ReactiveBackgroundComponent,
ItemModelComponent
],
imports: [
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 5a30802b..9e2bbc54 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -1,4 +1,5 @@
@import '~bootstrap/dist/css/bootstrap.min.css';
body {
- background-image: url('/assets/images/add_model_background.jpg');
+ /*background-image: url('/assets/images/add_model_background.jpg');*/
+ background-color: cornflowerblue;
} \ No newline at end of file