aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/app')
-rw-r--r--frontend/src/app/Shared.ts25
-rw-r--r--frontend/src/app/_data/Dataset.ts18
-rw-r--r--frontend/src/app/_data/Experiment.ts34
-rw-r--r--frontend/src/app/_data/Model.ts46
-rw-r--r--frontend/src/app/_data/Notification.ts8
-rw-r--r--frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css0
-rw-r--r--frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html41
-rw-r--r--frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts78
-rw-r--r--frontend/src/app/_elements/annvisual/annvisual.component.ts3
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.css15
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.html70
-rw-r--r--frontend/src/app/_elements/dataset-load/dataset-load.component.ts121
-rw-r--r--frontend/src/app/_elements/datatable/datatable.component.html46
-rw-r--r--frontend/src/app/_elements/datatable/datatable.component.ts2
-rw-r--r--frontend/src/app/_elements/item-predictor/item-predictor.component.ts3
-rw-r--r--frontend/src/app/_elements/loading/loading.component.css81
-rw-r--r--frontend/src/app/_elements/loading/loading.component.html11
-rw-r--r--frontend/src/app/_elements/loading/loading.component.spec.ts (renamed from frontend/src/app/_pages/add-model/add-model.component.spec.ts)12
-rw-r--r--frontend/src/app/_elements/loading/loading.component.ts15
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.css0
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.html221
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.spec.ts25
-rw-r--r--frontend/src/app/_elements/model-load/model-load.component.ts79
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.html8
-rw-r--r--frontend/src/app/_elements/navbar/navbar.component.ts4
-rw-r--r--frontend/src/app/_elements/notifications/notifications.component.html23
-rw-r--r--frontend/src/app/_elements/notifications/notifications.component.ts12
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.css0
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.html7
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.spec.ts25
-rw-r--r--frontend/src/app/_modals/alert-dialog/alert-dialog.component.ts28
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.html2
-rw-r--r--frontend/src/app/_modals/login-modal/login-modal.component.ts5
-rw-r--r--frontend/src/app/_modals/register-modal/register-modal.component.ts12
-rw-r--r--frontend/src/app/_pages/add-model/add-model.component.html487
-rw-r--r--frontend/src/app/_pages/add-model/add-model.component.ts510
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.html4
-rw-r--r--frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts2
-rw-r--r--frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts8
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.html39
-rw-r--r--frontend/src/app/_pages/my-datasets/my-datasets.component.ts57
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.html2
-rw-r--r--frontend/src/app/_pages/my-models/my-models.component.ts3
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.html2
-rw-r--r--frontend/src/app/_pages/my-predictors/my-predictors.component.ts37
-rw-r--r--frontend/src/app/_pages/predict/predict.component.html40
-rw-r--r--frontend/src/app/_pages/predict/predict.component.ts16
-rw-r--r--frontend/src/app/_pages/profile/profile.component.ts13
-rw-r--r--frontend/src/app/_services/datasets.service.ts8
-rw-r--r--frontend/src/app/_services/predictors.service.ts11
-rw-r--r--frontend/src/app/app-routing.module.ts5
-rw-r--r--frontend/src/app/app.module.ts20
-rw-r--r--frontend/src/app/experiment/experiment.component.css (renamed from frontend/src/app/_pages/add-model/add-model.component.css)4
-rw-r--r--frontend/src/app/experiment/experiment.component.html201
-rw-r--r--frontend/src/app/experiment/experiment.component.spec.ts25
-rw-r--r--frontend/src/app/experiment/experiment.component.ts118
-rw-r--r--frontend/src/app/material.module.ts7
58 files changed, 1485 insertions, 1239 deletions
diff --git a/frontend/src/app/Shared.ts b/frontend/src/app/Shared.ts
index 31afb1a6..86e26687 100644
--- a/frontend/src/app/Shared.ts
+++ b/frontend/src/app/Shared.ts
@@ -1,9 +1,32 @@
+import { ElementRef } from "@angular/core";
+import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
+
class Shared {
constructor(
public loggedIn: boolean,
public username: string = '',
- public photoId: string = '1'
+ public photoId: string = '1',
+ public dialog?: MatDialog
+ //public alertDialog?: ElementRef
) { }
+
+
+ openDialog(title: string, message: string): void {
+ console.log("USAO U OPEN DIALOG 1");
+
+ if (this.dialog) {
+ console.log("USAO U OPEN DIALOG 2");
+ const dialogRef = this.dialog.open(AlertDialogComponent, {
+ //width: '250px',
+ data: { title: title, message: message }
+ });
+ dialogRef.afterClosed().subscribe(res => {
+ //nesto
+ });
+ }
+ }
}
export default new Shared(false); \ No newline at end of file
diff --git a/frontend/src/app/_data/Dataset.ts b/frontend/src/app/_data/Dataset.ts
index c5b56957..dd751947 100644
--- a/frontend/src/app/_data/Dataset.ts
+++ b/frontend/src/app/_data/Dataset.ts
@@ -12,6 +12,22 @@ export default class Dataset {
public lastUpdated: Date = new Date(),
public username: string = '',
public delimiter: string = '',
- public hasHeader: boolean = true
+ public hasHeader: boolean = true,
+
+ public columnInfo: ColumnInfo[] = [],
+ public preview: string[][] = [[]]
+ ) { }
+}
+
+export class ColumnInfo {
+ constructor(
+ public name: string = '',
+ public isNumber: boolean = false,
+ public numNull: number = 0,
+ public uniqueValues?: string[],
+ public median?: number,
+ public mean?: number,
+ public min?: number,
+ public max?: number
) { }
} \ No newline at end of file
diff --git a/frontend/src/app/_data/Experiment.ts b/frontend/src/app/_data/Experiment.ts
new file mode 100644
index 00000000..10320ab6
--- /dev/null
+++ b/frontend/src/app/_data/Experiment.ts
@@ -0,0 +1,34 @@
+export default class Experiment {
+ _id: string = '';
+ constructor(
+ public name: string = 'Novi experiment',
+ public description: string = '',
+ public datasetId: string = '',
+ public inputColumns: string[] = [],
+ public columnToPredict: string = '',
+ public nullValues: NullValueOptions = NullValueOptions.DeleteRows,
+ public nullValuesReplacers: NullValReplacer[] = [],
+ public dateCreated: Date = new Date(),
+ public lastUpdated: Date = new Date()
+ ) { }
+}
+
+export enum NullValueOptions {
+ DeleteRows = 'delete_rows',
+ DeleteColumns = 'delete_columns',
+ Replace = 'replace'
+}
+
+export enum ReplaceWith {
+ None = 'Popuni...',
+ Mean = 'Srednja vrednost',
+ Median = 'Medijana',
+ Min = 'Minimum',
+ Max = 'Maksimum'
+}
+
+export class NullValReplacer {
+ "column": string;
+ "option": NullValueOptions;
+ "value": string;
+} \ No newline at end of file
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts
index d9ba7885..9ea437b1 100644
--- a/frontend/src/app/_data/Model.ts
+++ b/frontend/src/app/_data/Model.ts
@@ -7,11 +7,9 @@ export default class Model {
public description: string = '',
public dateCreated: Date = new Date(),
public lastUpdated: Date = new Date(),
- public datasetId: string = '',
+ public experimentId: string = '',
// Test set settings
- public inputColumns: string[] = [],
- public columnToPredict: string = '',
public randomOrder: boolean = true,
public randomTestSet: boolean = true,
public randomTestSetDistribution: number = 0.1, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U
@@ -26,11 +24,8 @@ export default class Model {
public hiddenLayers: number = 1,
public batchSize: number = 5,
public hiddenLayerActivationFunctions: string[] = ['sigmoid'],
- //public inputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid,
public username: string = '',
- public nullValues: NullValueOptions = NullValueOptions.DeleteRows,
- public nullValuesReplacers: NullValReplacer[] = [],
public metrics: string[] = [], // TODO add to add-model form
public epochs: number = 5 // TODO add to add-model form
) { }
@@ -85,7 +80,6 @@ export enum ActivationFunction {
Linear = 'linear',
//Sigmoid='sigmoid',
Softmax = 'softmax',
-
}
/*
export enum ActivationFunctionHiddenLayer
@@ -117,7 +111,6 @@ export enum LossFunction {
MeanSquaredError = 'mean_squared_error',
MeanSquaredLogarithmicError = 'mean_squared_logarithmic_error',
HuberLoss = 'Huber'
-
}
export enum LossFunctionRegression {
MeanAbsoluteError = 'mean_absolute_error',
@@ -168,31 +161,28 @@ export enum Metrics {
MSE = 'mse',
MAE = 'mae',
RMSE = 'rmse'
-
+
}
-export enum MetricsRegression
-{
+export enum MetricsRegression {
Mse = 'mse',
Mae = 'mae',
Mape = 'mape',
- Msle='msle',
- CosineProximity='cosine'
+ Msle = 'msle',
+ CosineProximity = 'cosine'
}
-export enum MetricsBinaryClassification
-{
- Accuracy='binary_accuracy',
- Auc="AUC",
- Precision='precision_score',
- Recall='recall_score',
- F1='f1_score',
-
+export enum MetricsBinaryClassification {
+ Accuracy = 'binary_accuracy',
+ Auc = "AUC",
+ Precision = 'precision_score',
+ Recall = 'recall_score',
+ F1 = 'f1_score',
+
}
-export enum MetricsMultiClassification
-{
- Accuracy='categorical_accuracy',
- Auc="AUC",
- Precision='precision_score',
- Recall='recall_score',
- F1='f1_score',
+export enum MetricsMultiClassification {
+ Accuracy = 'categorical_accuracy',
+ Auc = "AUC",
+ Precision = 'precision_score',
+ Recall = 'recall_score',
+ F1 = 'f1_score',
}
diff --git a/frontend/src/app/_data/Notification.ts b/frontend/src/app/_data/Notification.ts
new file mode 100644
index 00000000..181bb332
--- /dev/null
+++ b/frontend/src/app/_data/Notification.ts
@@ -0,0 +1,8 @@
+export default class Notification {
+ _id: string = '';
+ constructor(
+ public title: string = 'Treniranje u toku...',
+ public id: string = '042',
+ public progress: number = 0.5
+ ) { }
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.css
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html
new file mode 100644
index 00000000..dfeb4f62
--- /dev/null
+++ b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.html
@@ -0,0 +1,41 @@
+<div class="row mb-4">
+ <div class="col-2">
+ </div>
+ <div class="col-3">
+ <label for="name" class="col-form-label">Naziv dataseta:</label>
+ <input type="text" class="form-control mb-1" name="name" placeholder="Naziv..." [(ngModel)]="dataset.name">
+
+ <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
+ <div>
+ <textarea class="form-control" name="desc" rows="3" [(ngModel)]="dataset.description"></textarea>
+ </div>
+
+ <label for="checkboxIsPublic" class="form-check-label mt-3 mb-1">Želite li da dataset bude javan?
+ <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.isPublic" (change)="checkAccessible()" type="checkbox"
+ value="" id="checkboxIsPublic">
+ </label>
+
+ <label for="checkboxAccessibleByLink" class="form-check-label">Želite li da bude deljiv linkom? &nbsp;
+ <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.accessibleByLink" type="checkbox"
+ value="" id="checkboxAccessibleByLink">
+ </label>
+ </div>
+ <div class="col-1">
+ </div>
+ <div class="col-4 mt-4">
+
+ <input list=delimiterOptions placeholder="Izaberite ili ukucajte delimiter za .csv fajl" class="form-control mt-2"
+ [(ngModel)]="dataset.delimiter" (input)="update()">
+ <datalist id=delimiterOptions>
+ <option *ngFor="let option of delimiterOptions">{{option}}</option>
+ </datalist>
+
+ <label for="type" class="form-check-label my-5">Da li .csv ima header?
+ <input class="mx-3 form-check-input" type="checkbox" (input)="update()" [(ngModel)]="dataset.hasHeader" type="checkbox"
+ value="" id="checkboxHeader" checked>
+ </label>
+ <br>
+ <input id="fileInput" class="form-control" type="file" class="upload" (change)="changeListener($event)"
+ accept=".csv">
+ </div>
+ </div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts
new file mode 100644
index 00000000..a9ea25b4
--- /dev/null
+++ b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AddNewDatasetComponent } from './add-new-dataset.component';
+
+describe('AddNewDatasetComponent', () => {
+ let component: AddNewDatasetComponent;
+ let fixture: ComponentFixture<AddNewDatasetComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ AddNewDatasetComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AddNewDatasetComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts
new file mode 100644
index 00000000..fceb53cf
--- /dev/null
+++ b/frontend/src/app/_elements/add-new-dataset/add-new-dataset.component.ts
@@ -0,0 +1,78 @@
+import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
+import { NgxCsvParser, NgxCSVParserError } from 'ngx-csv-parser';
+import Dataset from 'src/app/_data/Dataset';
+
+@Component({
+ selector: 'app-add-new-dataset',
+ templateUrl: './add-new-dataset.component.html',
+ styleUrls: ['./add-new-dataset.component.css']
+})
+export class AddNewDatasetComponent {
+
+ @Output() loaded = new EventEmitter<string>();
+
+ delimiterOptions: Array<string> = [",", ";", "\t", "razmak", "|"]; //podrazumevano ","
+
+ //hasHeader: boolean = true;
+ hasInput: boolean = false;
+
+ csvRecords: any[] = [];
+ files: File[] = [];
+ rowsNumber: number = 0;
+ colsNumber: number = 0;
+
+ dataset: Dataset; //dodaj ! potencijalno
+
+ constructor(private ngxCsvParser: NgxCsvParser) {
+ this.dataset = new Dataset();
+ }
+
+ //@ViewChild('fileImportInput', { static: false }) fileImportInput: any; cemu je ovo sluzilo?
+
+ changeListener($event: any): void {
+ this.files = $event.srcElement.files;
+ if (this.files.length == 0 || this.files[0] == null) {
+ //console.log("NEMA FAJLA");
+ //this.loaded.emit("not loaded");
+ this.hasInput = false;
+ return;
+ }
+ else
+ this.hasInput = true;
+
+ this.update();
+ }
+
+ update() {
+
+ if (this.files.length < 1)
+ return;
+
+ this.ngxCsvParser.parse(this.files[0], { header: false, delimiter: (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "") ? "," : this.dataset.delimiter })
+ .pipe().subscribe((result) => {
+
+ console.log('Result', result);
+ if (result.constructor === Array) {
+ this.csvRecords = result;
+ if (this.dataset.hasHeader)
+ this.rowsNumber = this.csvRecords.length - 1;
+ else
+ this.rowsNumber = this.csvRecords.length;
+ this.colsNumber = this.csvRecords[0].length;
+
+ if (this.dataset.hasHeader) //kasnije dodati opciju kada nema header da korisnik rucno unosi header-e
+ this.dataset.header = this.csvRecords[0];
+
+ this.loaded.emit("loaded");
+ }
+ }, (error: NgxCSVParserError) => {
+ console.log('Error', error);
+ });
+ }
+
+ checkAccessible() {
+ if (this.dataset.isPublic)
+ this.dataset.accessibleByLink = true;
+ }
+
+}
diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.ts b/frontend/src/app/_elements/annvisual/annvisual.component.ts
index 53e4e2ca..df0a3898 100644
--- a/frontend/src/app/_elements/annvisual/annvisual.component.ts
+++ b/frontend/src/app/_elements/annvisual/annvisual.component.ts
@@ -18,7 +18,7 @@ export class AnnvisualComponent implements OnInit {
let hiddenlayerstring: string = '';
let digraphstring: string = 'digraph {';
- for (let i = 0; i < this.model.inputColumns.length; i++) {
+ for (let i = 0; i < /*this.model.inputColumns.length*/ 10; i++) {
inputlayerstring = inputlayerstring + 'i' + i + ',';
}
inputlayerstring = inputlayerstring.slice(0, -1);
@@ -35,7 +35,6 @@ export class AnnvisualComponent implements OnInit {
}
digraphstring = digraphstring + 'o}';
-
graphviz('#graph').renderDot(digraphstring);
}
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.css b/frontend/src/app/_elements/dataset-load/dataset-load.component.css
index 05819702..54e0738e 100644
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.css
+++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.css
@@ -1,6 +1,13 @@
-#divInputs {
- margin-left: 20px;
+.btnType1 {
+ background-color: #003459;
+ color: white;
}
-#divOutputs {
- margin-left: 20px;
+.btnType2 {
+ background-color: white;
+ color: #003459;
+ border-color: #003459;
+}
+.selectedDatasetClass {
+ /*border-color: 2px solid #003459;*/
+ background-color: lightblue;
} \ No newline at end of file
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.html b/frontend/src/app/_elements/dataset-load/dataset-load.component.html
index 76e46092..674e5990 100644
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.html
+++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.html
@@ -1,44 +1,42 @@
<div>
- <div class="row mb-4">
- <div class="col-2">
- </div>
- <div class="col-3">
- <label for="name" class="col-form-label">Naziv dataseta:</label>
- <input type="text" class="form-control mb-1" name="name" placeholder="Naziv..." [(ngModel)]="dataset.name">
-
- <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
- <div>
- <textarea class="form-control" name="desc" rows="3" [(ngModel)]="dataset.description"></textarea>
- </div>
+ <!--Sklonjeno ucitavanje novog dataseta i sve opcije u vezi sa tim, premesteno u add-new-dataset-->
- <label for="checkboxIsPublic" class="form-check-label mt-3 mb-1">Želite li da dataset bude javan?
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.isPublic" (change)="checkAccessible()" type="checkbox"
- value="" id="checkboxIsPublic">
- </label>
-
- <label for="checkboxAccessibleByLink" class="form-check-label">Želite li da bude deljiv linkom? &nbsp;
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="dataset.accessibleByLink" type="checkbox"
- value="" id="checkboxAccessibleByLink">
- </label>
- </div>
+ <div class="col-12 d-flex my-5">
+ <h2 class="">Izvor podataka:</h2>
<div class="col-1">
</div>
- <div class="col-4 mt-4">
-
- <input list=delimiterOptions placeholder="Izaberite ili ukucajte delimiter za .csv fajl" class="form-control mt-2"
- [(ngModel)]="dataset.delimiter" (input)="update()">
- <datalist id=delimiterOptions>
- <option *ngFor="let option of delimiterOptions">{{option}}</option>
- </datalist>
+ <button type="button" id="btnMyDataset" class="btn" (click)="viewMyDatasetsForm()"
+ [ngClass]="{'btnType1': showMyDatasets, 'btnType2': !showMyDatasets}">
+ Izaberite dataset iz kolekcije
+ </button>
+ <h3 class="mt-3 mx-3">ili</h3>
+ <button type="button" id="btnNewDataset" class="btn" (click)="viewNewDatasetForm()"
+ [ngClass]="{'btnType1': !showMyDatasets, 'btnType2': showMyDatasets}">
+ 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|filter:term"
+ [ngClass]="{'selectedDatasetClass': this.selectedDataset == dataset}">
+ <app-item-dataset name="usersDataset" [dataset]="dataset"
+ (click)="selectThisDataset(dataset);"></app-item-dataset>
+ </li>
+ </ul>
+ </div>
+ </div>
- <label for="type" class="form-check-label my-5">Da li .csv ima header?
- <input class="mx-3 form-check-input" type="checkbox" (input)="update()" [(ngModel)]="dataset.hasHeader" type="checkbox"
- value="" id="checkboxHeader" checked>
- </label>
- <br>
- <input id="fileInput" class="form-control" type="file" class="upload" (change)="changeListener($event)"
- accept=".csv">
- </div>
+ <app-add-new-dataset [style]="(showMyDatasets)?'display:none;visibility:hidden;':''" id="dataset"
+ (loaded)="datasetLoaded = true; selectedDataset = addNewDatasetComponent?.dataset; datasetFile = addNewDatasetComponent?.csvRecords; datasetHasHeader = addNewDatasetComponent?.dataset!.hasHeader">
+ </app-add-new-dataset>
+ <div class="px-5 mt-5">
+ <app-datatable [data]="datasetFile" [hasHeader]="datasetHasHeader"></app-datatable>
</div>
+
</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts
index f9343117..ed71dc3c 100644
--- a/frontend/src/app/_elements/dataset-load/dataset-load.component.ts
+++ b/frontend/src/app/_elements/dataset-load/dataset-load.component.ts
@@ -1,6 +1,12 @@
-import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
-import { NgxCsvParser, NgxCSVParserError } from 'ngx-csv-parser';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { AddNewDatasetComponent } from '../add-new-dataset/add-new-dataset.component';
+import { ModelsService } from 'src/app/_services/models.service';
+import shared from 'src/app/Shared';
import Dataset from 'src/app/_data/Dataset';
+import { DatatableComponent } from 'src/app/_elements/datatable/datatable.component';
+import { DatasetsService } from 'src/app/_services/datasets.service';
+import { CsvParseService } from 'src/app/_services/csv-parse.service';
+import { Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-dataset-load',
@@ -9,70 +15,77 @@ import Dataset from 'src/app/_data/Dataset';
})
export class DatasetLoadComponent {
- @Output() loaded = new EventEmitter<string>();
+ @Output() selectedDatasetChangeEvent = new EventEmitter<Dataset>();
- delimiterOptions: Array<string> = [",", ";", "\t", "razmak", "|"]; //podrazumevano ","
+ @ViewChild(AddNewDatasetComponent) addNewDatasetComponent?: AddNewDatasetComponent;
+ @ViewChild(AddNewDatasetComponent) datatable?: DatatableComponent;
+ datasetLoaded: boolean = false;
+ selectedDatasetLoaded: boolean = false;
- //hasHeader: boolean = true;
- hasInput: boolean = false;
+ showMyDatasets: boolean = true;
+ myDatasets?: Dataset[];
+ existingDatasetSelected: boolean = false;
+ selectedDataset?: Dataset;
+ otherDataset?: Dataset;
+ otherDatasetFile?: any[];
+ datasetFile?: any[];
+ datasetHasHeader?: boolean = true;
- csvRecords: any[] = [];
- files: File[] = [];
- rowsNumber: number = 0;
- colsNumber: number = 0;
+ term: string = "";
- dataset: Dataset; //dodaj ! potencijalno
-
- constructor(private ngxCsvParser: NgxCsvParser) {
- this.dataset = new Dataset();
+ constructor(private models: ModelsService, private datasets: DatasetsService, private csv: CsvParseService) {
+ this.datasets.getMyDatasets().subscribe((datasets) => {
+ this.myDatasets = datasets;
+ });
}
- @ViewChild('fileImportInput', { static: false }) fileImportInput: any;
-
- changeListener($event: any): void {
- this.files = $event.srcElement.files;
- if (this.files.length == 0 || this.files[0] == null) {
- //console.log("NEMA FAJLA");
- //this.loaded.emit("not loaded");
- this.hasInput = false;
- return;
- }
- else
- this.hasInput = true;
-
- this.update();
+ viewMyDatasetsForm() {
+ this.showMyDatasets = true;
+ this.resetSelectedDataset();
+ //this.resetCbsAndRbs(); //TREBA DA SE DESI
+ }
+ viewNewDatasetForm() {
+ this.showMyDatasets = false;
+ this.resetSelectedDataset();
+ //this.resetCbsAndRbs(); //TREBA DA SE DESI
}
- update() {
-
- if (this.files.length < 1)
- return;
-
- this.ngxCsvParser.parse(this.files[0], { header: false, delimiter: (this.dataset.delimiter == "razmak") ? " " : (this.dataset.delimiter == "") ? "," : this.dataset.delimiter })
- .pipe().subscribe((result) => {
-
- console.log('Result', result);
- if (result.constructor === Array) {
- this.csvRecords = result;
- if (this.dataset.hasHeader)
- this.rowsNumber = this.csvRecords.length - 1;
+ selectThisDataset(dataset: Dataset) {
+ this.selectedDataset = dataset;
+ this.selectedDatasetLoaded = false;
+ this.existingDatasetSelected = true;
+ this.datasetHasHeader = this.selectedDataset.hasHeader;
+
+ this.datasets.getDatasetFile(dataset.fileId).subscribe((file: string | undefined) => {
+ if (file) {
+ this.datasetFile = this.csv.csvToArray(file, (dataset.delimiter == "razmak") ? " " : (dataset.delimiter == "") ? "," : dataset.delimiter);
+ /*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
- this.rowsNumber = this.csvRecords.length;
- this.colsNumber = this.csvRecords[0].length;
+ break; //nema potrebe dalje
+ }*/
+ //console.log(this.datasetFile);
+ //this.resetCbsAndRbs(); //TREBA DA SE DESI
+ //this.refreshThreeNullValueRadioOptions(); //TREBA DA SE DESI
+ this.selectedDatasetLoaded = true;
+ //this.scrollToNextForm();
+ }
+ });
+ }
- if (this.dataset.hasHeader) //kasnije dodati opciju kada nema header da korisnik rucno unosi header-e
- this.dataset.header = this.csvRecords[0];
+ resetSelectedDataset(): boolean {
+ const temp = this.selectedDataset;
+ this.selectedDataset = this.otherDataset;
+ this.otherDataset = temp;
+ const tempFile = this.datasetFile;
+ this.datasetFile = this.otherDatasetFile;
+ this.otherDatasetFile = tempFile;
- this.loaded.emit("loaded");
- }
- }, (error: NgxCSVParserError) => {
- console.log('Error', error);
- });
- }
+ this.selectedDatasetChangeEvent.emit(this.selectedDataset);
- checkAccessible() {
- if (this.dataset.isPublic)
- this.dataset.accessibleByLink = true;
+ return true;
}
+
}
diff --git a/frontend/src/app/_elements/datatable/datatable.component.html b/frontend/src/app/_elements/datatable/datatable.component.html
index bd9e7a13..8fcd44ac 100644
--- a/frontend/src/app/_elements/datatable/datatable.component.html
+++ b/frontend/src/app/_elements/datatable/datatable.component.html
@@ -1,25 +1,31 @@
<div *ngIf="data">
- <div class="table-responsive" style="max-height: 50vh; max-width: 100%; overflow: scroll;">
- <table *ngIf="hasHeader" class="table table-bordered table-light">
- <thead>
- <tr>
- <th *ngFor="let item of data[0]; let i = index">{{item}}</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let row of data | slice:1">
- <td *ngFor="let col of row">{{col}}</td>
- </tr>
- </tbody>
- </table>
+ <div class="table-responsive" style="height: 34rem; overflow: auto; border-radius: 5px;" class="mh-5">
+ <div *ngIf="!loaded" style="background-color: #003459; width: 100%; height: 100%;"
+ class="d-flex justify-content-center align-items-center">
+ <app-loading></app-loading>
+ </div>
+ <div *ngIf="loaded">
+ <table *ngIf="hasHeader" class="table table-bordered table-light">
+ <thead>
+ <tr>
+ <th *ngFor="let item of data[0]; let i = index">{{item}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let row of data | slice:1">
+ <td *ngFor="let col of row">{{col}}</td>
+ </tr>
+ </tbody>
+ </table>
- <table *ngIf="data.length > 0 && !hasHeader" class="table table-bordered table-light">
- <tbody>
- <tr *ngFor="let row of data">
- <td *ngFor="let col of row">{{col}}</td>
- </tr>
- </tbody>
- </table>
+ <table *ngIf="data.length > 0 && !hasHeader" class="table table-bordered table-light">
+ <tbody>
+ <tr *ngFor="let row of data">
+ <td *ngFor="let col of row">{{col}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
</div>
<div id="info">
diff --git a/frontend/src/app/_elements/datatable/datatable.component.ts b/frontend/src/app/_elements/datatable/datatable.component.ts
index d3740d83..3343f6f0 100644
--- a/frontend/src/app/_elements/datatable/datatable.component.ts
+++ b/frontend/src/app/_elements/datatable/datatable.component.ts
@@ -11,6 +11,8 @@ export class DatatableComponent implements OnInit {
@Input() data?: any[] = [];
+ loaded = false;
+
constructor() { }
ngOnInit(): void {
diff --git a/frontend/src/app/_elements/item-predictor/item-predictor.component.ts b/frontend/src/app/_elements/item-predictor/item-predictor.component.ts
index 41d2ab9c..246032e0 100644
--- a/frontend/src/app/_elements/item-predictor/item-predictor.component.ts
+++ b/frontend/src/app/_elements/item-predictor/item-predictor.component.ts
@@ -17,8 +17,7 @@ export class ItemPredictorComponent implements OnInit {
}
openPredictor() {
- this.router.navigate(['predict/'+ '6245a5958a9c76c1bf7ff9b6']);
- //this.router.navigate(['predict'+this.predictor._id]);
+ this.router.navigate(['predict/'+ this.predictor._id]);
}
}
diff --git a/frontend/src/app/_elements/loading/loading.component.css b/frontend/src/app/_elements/loading/loading.component.css
new file mode 100644
index 00000000..f39f60ee
--- /dev/null
+++ b/frontend/src/app/_elements/loading/loading.component.css
@@ -0,0 +1,81 @@
+.lds-grid {
+ display: inline-block;
+ position: relative;
+ width: 80px;
+ height: 80px;
+}
+
+.lds-grid div {
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background: #fff;
+ animation: lds-grid 1.2s linear infinite;
+}
+
+.lds-grid div:nth-child(1) {
+ top: 8px;
+ left: 8px;
+ animation-delay: 0s;
+}
+
+.lds-grid div:nth-child(2) {
+ top: 8px;
+ left: 32px;
+ animation-delay: -0.4s;
+}
+
+.lds-grid div:nth-child(3) {
+ top: 8px;
+ left: 56px;
+ animation-delay: -0.8s;
+}
+
+.lds-grid div:nth-child(4) {
+ top: 32px;
+ left: 8px;
+ animation-delay: -0.4s;
+}
+
+.lds-grid div:nth-child(5) {
+ top: 32px;
+ left: 32px;
+ animation-delay: -0.8s;
+}
+
+.lds-grid div:nth-child(6) {
+ top: 32px;
+ left: 56px;
+ animation-delay: -1.2s;
+}
+
+.lds-grid div:nth-child(7) {
+ top: 56px;
+ left: 8px;
+ animation-delay: -0.8s;
+}
+
+.lds-grid div:nth-child(8) {
+ top: 56px;
+ left: 32px;
+ animation-delay: -1.2s;
+}
+
+.lds-grid div:nth-child(9) {
+ top: 56px;
+ left: 56px;
+ animation-delay: -1.6s;
+}
+
+@keyframes lds-grid {
+
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0.5;
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/_elements/loading/loading.component.html b/frontend/src/app/_elements/loading/loading.component.html
new file mode 100644
index 00000000..d2c7b74e
--- /dev/null
+++ b/frontend/src/app/_elements/loading/loading.component.html
@@ -0,0 +1,11 @@
+<div class="lds-grid">
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_pages/add-model/add-model.component.spec.ts b/frontend/src/app/_elements/loading/loading.component.spec.ts
index 2926e1c4..7aacfad9 100644
--- a/frontend/src/app/_pages/add-model/add-model.component.spec.ts
+++ b/frontend/src/app/_elements/loading/loading.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { AddModelComponent } from './add-model.component';
+import { LoadingComponent } from './loading.component';
-describe('AddModelComponent', () => {
- let component: AddModelComponent;
- let fixture: ComponentFixture<AddModelComponent>;
+describe('LoadingComponent', () => {
+ let component: LoadingComponent;
+ let fixture: ComponentFixture<LoadingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ AddModelComponent ]
+ declarations: [ LoadingComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(AddModelComponent);
+ fixture = TestBed.createComponent(LoadingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/frontend/src/app/_elements/loading/loading.component.ts b/frontend/src/app/_elements/loading/loading.component.ts
new file mode 100644
index 00000000..4dff0cdf
--- /dev/null
+++ b/frontend/src/app/_elements/loading/loading.component.ts
@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-loading',
+ templateUrl: './loading.component.html',
+ styleUrls: ['./loading.component.css']
+})
+export class LoadingComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+}
diff --git a/frontend/src/app/_elements/model-load/model-load.component.css b/frontend/src/app/_elements/model-load/model-load.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_elements/model-load/model-load.component.css
diff --git a/frontend/src/app/_elements/model-load/model-load.component.html b/frontend/src/app/_elements/model-load/model-load.component.html
new file mode 100644
index 00000000..0c6735a9
--- /dev/null
+++ b/frontend/src/app/_elements/model-load/model-load.component.html
@@ -0,0 +1,221 @@
+<div>
+ <div class="form-group row mt-3 mb-2 d-flex justify-content-center">
+ <h2 class="col-2"> Nov model: </h2>
+ <div class="col-3">
+ <label for="name" class="col-form-label">Naziv modela:</label>
+ <input type="text" class="form-control" name="name" placeholder="Naziv..." [(ngModel)]="newModel.name">
+ </div>
+ <div class="col-5">
+ <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
+ <div>
+ <textarea class="form-control" name="desc" rows="3" [(ngModel)]="newModel.description"></textarea>
+ </div>
+ </div>
+ <div class="col-2">
+ <label for="dateCreated" class="col-form-label">Datum:</label> &nbsp;&nbsp;
+ <input type="text" class="form-control-plaintext" id="dateCreated" placeholder="--/--/--"
+ value="{{newModel.dateCreated | date: 'dd/MM/yyyy'}}" readonly>
+ </div>
+ </div>
+ <h2 class="mt-5 mb-4">Parametri treniranja:</h2>
+ <div>
+ <div class="row p-2">
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <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"
+ (change)="filterOptions()">
+ <option
+ *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="hiddenLayers" class="col-form-label">Broj skrivenih slojeva: </label>
+ </div>
+ <div class="col-1">
+ <input type="number" min="1" class="form-control" name="hiddenLayers"
+ [(ngModel)]="newModel.hiddenLayers"
+ (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])">
+ </div>
+ </div>
+
+ <div class="row p-2">
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="encoding" class="col-form-label">Enkoding: </label>
+ </div>
+ <div class="col-2">
+ <select id=encodingOptions class="form-control" name="encoding" [(ngModel)]="newModel.encoding">
+ <option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
+
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="hiddenLayerNeurons" class="col-form-label">Broj neurona skrivenih slojeva: </label>
+ </div>
+ <div class="col-1">
+ <input type="number" min="1" class="form-control" name="hiddenLayerNeurons"
+ [(ngModel)]="newModel.hiddenLayerNeurons">
+ </div>
+ </div>
+
+ <div class="row p-2">
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="optimizer" class="col-form-label">Optimizacija: </label>
+ </div>
+ <div class="col-2">
+ <select id=optimizerOptions class="form-control" name="optimizer" [(ngModel)]="newModel.optimizer">
+ <option *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="batchSize" class="col-form-label">Broj uzorka po iteraciji: </label>
+ </div>
+ <div class="col-1">
+ <input type="number" min="1" class="form-control" name="batchSize" [(ngModel)]="newModel.batchSize">
+ </div>
+ </div>
+ <div class="row p-2">
+ <div class="col-1">
+ </div>
+ <div class="col-3">
+ <label for="lossFunction" class="col-form-label">Funkcija obrade gubitka: </label>
+ </div>
+ <div class="col-2">
+ <select id=lossFunctionOptions class="form-control" name="lossFunction"
+ [(ngModel)]="newModel.lossFunction" aria-checked="true">
+ <option
+ *ngFor="let option of Object.keys(lossFunction); let optionName of Object.values(lossFunction)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
+ <div class="col-1"></div>
+ <div class="col-3 mt-2">
+ <label for="type" class="form-check-label">Nasumičan redosled podataka?</label>
+ <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="newModel.randomOrder" type="checkbox"
+ value="" checked>
+ </div>
+ </div>
+ <div class="border m-3">
+ <div class="row p-2 m-2">
+ <div class="col-4">
+ <label for="splitYesNo" class="form-check-label">
+ <h3>Podela test skupa:&nbsp;&nbsp;
+ <input id="splitYesNo" class="form-check-input" type="checkbox"
+ [checked]="newModel.randomTestSet"
+ (change)="newModel.randomTestSet = !newModel.randomTestSet">
+ </h3>
+ </label>
+ </div>
+ <div class="col-8">
+ trening
+ <mat-slider style="width: 85%;" min="10" max="90" step="10" value="10"
+ name="randomTestSetDistribution" thumbLabel [disabled]="!newModel.randomTestSet"
+ [(ngModel)]="tempTestSetDistribution">
+ </mat-slider>
+ test
+ </div>
+ </div>
+
+ <div class="row p-2 mx-2">
+ <div class="col-4">
+ <label for="percentage" class="form-label">Procenat podataka koji se uzima za trening
+ skup:</label>
+ </div>
+ <div class="col-2">
+ <input id="percentage" type="number" class="form-control" min="10" max="90" step="10" value="90"
+ [(ngModel)]="tempTestSetDistribution" [disabled]="!newModel.randomTestSet">
+ </div>
+ </div>
+ </div>
+ <h3>Aktivacione funkcije:</h3>
+
+ <div class="row p-2 m-2" style="align-self: center;">
+ <div class="col-3">
+ <label for="hiddenLayerActivationFunction" class="col-form-label" style="text-align: center;">Funkcija
+ aktivacije skrivenih
+ slojeva:</label>
+ </div>
+ <div class="col-3">
+ <div *ngFor="let item of [].constructor(newModel.hiddenLayers); let i = index">
+ <div class="input-group mb-2">
+ <div class="input-group-prepend">
+ <span class="input-group-text">#{{i+1}}</span>
+ </div>
+ <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>
+ <div class="col-3">
+ <label for="outputLayerActivationFunction" class="col-form-label" style="text-align: center;">Funkcija
+ aktivacije izlaznog
+ sloja:</label>
+ </div>
+ <div class="col-3">
+ <select id=outputLayerActivationFunctionOptions class="form-control"
+ name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction">
+ <option
+ *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ </div>
+ <div class="col">
+ </div>
+ </div>
+ </div>
+ <br><br>
+ <hr>
+ <div class="form-check form-check-inline overflow-auto " style="width: max-content;">
+ <h3>Izaberite metrike:</h3>
+ <div id="divMetricsinput">
+
+ <div *ngFor="let option of Object.keys(metrics); let optionName of Object.values(metrics) "
+ class="form-check form-check-inline">
+
+ <input name="cbmetrics" class="form-check-input" type="checkbox" value="{{option}}"
+ id="metrics_{{option}}" style="float: left;">
+ <label class="form-check-label" for="metrics_{{option}}" for="inlineCheckbox2">
+ {{optionName}}
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group row mt-5 mb-3">
+ <div class="col"></div>
+ <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="addModel();">Sačuvaj
+ model</button>
+ <div class="col"></div>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/model-load/model-load.component.spec.ts b/frontend/src/app/_elements/model-load/model-load.component.spec.ts
new file mode 100644
index 00000000..1dafd966
--- /dev/null
+++ b/frontend/src/app/_elements/model-load/model-load.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ModelLoadComponent } from './model-load.component';
+
+describe('ModelLoadComponent', () => {
+ let component: ModelLoadComponent;
+ let fixture: ComponentFixture<ModelLoadComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ModelLoadComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ModelLoadComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_elements/model-load/model-load.component.ts b/frontend/src/app/_elements/model-load/model-load.component.ts
new file mode 100644
index 00000000..1d38de68
--- /dev/null
+++ b/frontend/src/app/_elements/model-load/model-load.component.ts
@@ -0,0 +1,79 @@
+import { Component, OnInit } from '@angular/core';
+import Shared from 'src/app/Shared';
+import Model, { ActivationFunction, Encoding, LossFunction, LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, Metrics, MetricsBinaryClassification, MetricsMultiClassification, MetricsRegression, NullValueOptions, Optimizer, ProblemType } from 'src/app/_data/Model';
+import { ModelsService } from 'src/app/_services/models.service';
+
+@Component({
+ selector: 'app-model-load',
+ templateUrl: './model-load.component.html',
+ styleUrls: ['./model-load.component.css']
+})
+export class ModelLoadComponent implements OnInit {
+
+ newModel: Model = new Model();
+
+ ProblemType = ProblemType;
+ Encoding = Encoding;
+ ActivationFunction = ActivationFunction;
+ metrics: any = Metrics;
+ LossFunction = LossFunction;
+ Optimizer = Optimizer;
+ Object = Object;
+ document = document;
+ shared = Shared;
+
+ term: string = "";
+ selectedProblemType: string = '';
+ selectedMetrics = [];
+ tempTestSetDistribution = 90;
+ lossFunction: any = LossFunction;
+
+ constructor(private models: ModelsService) { }
+
+ ngOnInit(): void {
+ }
+
+ getMetrics() {
+ this.newModel.metrics = [];
+ let cb = document.getElementsByName("cbmetrics");
+
+ for (let i = 0; i < cb.length; i++) {
+ let chb = <HTMLInputElement>cb[i];
+ if (chb.checked == true)
+ this.newModel.metrics.push(chb.value);
+ }
+ }
+
+ addModel() {
+ this.getMetrics();
+
+ this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10;
+ this.newModel.username = Shared.username;
+
+ this.models.addModel(this.newModel).subscribe((response) => {
+ Shared.openDialog('Model dodat', 'Model je uspešno dodat u bazu.');
+ // treba da se selektuje nov model u listi modela
+ }, (error) => {
+ Shared.openDialog('Greška', 'Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom.');
+ });
+ }
+
+ filterOptions() {
+ switch (this.newModel.type) {
+ case 'regresioni':
+ this.lossFunction = LossFunctionRegression;
+ this.metrics = MetricsRegression;
+ break;
+ case 'binarni-klasifikacioni':
+ this.lossFunction = LossFunctionBinaryClassification;
+ this.metrics = MetricsBinaryClassification;
+ break;
+ case 'multi-klasifikacioni':
+ this.lossFunction = LossFunctionMultiClassification;
+ this.metrics = MetricsMultiClassification;
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/frontend/src/app/_elements/navbar/navbar.component.html b/frontend/src/app/_elements/navbar/navbar.component.html
index 82a1ea07..dbee4773 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.html
+++ b/frontend/src/app/_elements/navbar/navbar.component.html
@@ -8,8 +8,9 @@
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li><a routerLink="" class="nav-link px-2"
[class]="(currentUrl === '') ? 'text-secondary' : 'text-white'">Početna</a></li>
- <li><a routerLink="add-model" class="nav-link px-2"
- [class]="(currentUrl === '/add-model') ? 'text-secondary' : 'text-white'">Dodaj model</a></li>
+ <li><a routerLink="experiment" class="nav-link px-2"
+ [class]="(currentUrl === '/add-model') ? 'text-secondary' : 'text-white'">Eksperimentiši</a>
+ </li>
<li><a routerLink="my-predictors" class="nav-link px-2"
[class]="(currentUrl === '/my-predictors') ? 'text-secondary' : 'text-white' + (shared.loggedIn) ? '' : 'disabled'">Predvidi</a>
</li>
@@ -18,7 +19,8 @@
<div *ngIf="shared.loggedIn" class="dropdown text-end">
<a href="#" class="d-block link-light text-decoration-none dropdown-toggle" id="dropdownUser1"
data-bs-toggle="dropdown" aria-expanded="false">
- <img [src]="'/assets/profilePictures/'+ shared.photoId +'.png'" alt="mdo" width="32" height="32" class="rounded-circle">
+ <img [src]="'/assets/profilePictures/'+ shared.photoId +'.png'" alt="mdo" width="32" height="32"
+ class="rounded-circle">
</a>
<ul class="dropdown-menu text-small" aria-labelledby="dropdownUser1"
style="position: absolute; inset: 0px 0px auto auto; margin: 0px; transform: translate(0px, 34px);"
diff --git a/frontend/src/app/_elements/navbar/navbar.component.ts b/frontend/src/app/_elements/navbar/navbar.component.ts
index 2e4bde91..368508ed 100644
--- a/frontend/src/app/_elements/navbar/navbar.component.ts
+++ b/frontend/src/app/_elements/navbar/navbar.component.ts
@@ -3,6 +3,7 @@ import { Location } from '@angular/common';
import { AuthService } from '../../_services/auth.service';
import shared from 'src/app/Shared';
import { UserInfoService } from 'src/app/_services/user-info.service';
+import { MatDialog } from '@angular/material/dialog';
@Component({
selector: 'app-navbar',
@@ -14,7 +15,8 @@ export class NavbarComponent implements OnInit {
currentUrl: string;
shared = shared;
- constructor(public location: Location, private auth: AuthService, private userInfoService: UserInfoService) {
+ constructor(public location: Location, private auth: AuthService, private userInfoService: UserInfoService, private matDialog: MatDialog) {
+ shared.dialog = matDialog;
this.currentUrl = this.location.path();
this.location.onUrlChange(() => {
this.currentUrl = this.location.path();
diff --git a/frontend/src/app/_elements/notifications/notifications.component.html b/frontend/src/app/_elements/notifications/notifications.component.html
index d1da41b4..0b87e4fc 100644
--- a/frontend/src/app/_elements/notifications/notifications.component.html
+++ b/frontend/src/app/_elements/notifications/notifications.component.html
@@ -1,3 +1,20 @@
-<div *ngIf="notifications" class="position-fixed card card-body bg-dark text-white m-3" style="bottom: 0; right: 0;">
- <h3>Notifikacije</h3>
-</div> \ No newline at end of file
+<div *ngIf="notifications" class="position-fixed card card-body p-1 m-3" style="bottom: 0; right: 0; width: 18rem;">
+ <h2 class="m-auto" (click)="closed = !closed;" data-bs-toggle="collapse" href="#collapseNotifs" role="button"
+ aria-expanded="true" aria-controls="collapseNotifs">Notifikacije
+ <button class="border-0 bg-white">
+ <mat-icon class="position-absolute" style="top: 8px; right: 12px;">{{closed ? 'keyboard_arrow_up' :
+ 'keyboard_arrow_down'}}</mat-icon>
+ </button>
+ </h2>
+
+ <div id="collapseNotifs" class="collapse show">
+ <div *ngFor="let notification of notifications" class="p-2 m-1 border rounded">
+ <div class="d-flex flex-row">
+ <p>{{notification.title}}</p>
+ </div>
+ <div class="border-3 border-primary bg-dark m-1" style="height: 5px; margin-top: -10px !important;">
+ <div class="bg-primary" style="height: 5px;" [style]="'width: '+(notification.progress*100)+'%;'">
+ </div>
+ </div>
+ </div>
+ </div> \ No newline at end of file
diff --git a/frontend/src/app/_elements/notifications/notifications.component.ts b/frontend/src/app/_elements/notifications/notifications.component.ts
index 6c1d555b..82613448 100644
--- a/frontend/src/app/_elements/notifications/notifications.component.ts
+++ b/frontend/src/app/_elements/notifications/notifications.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { WebSocketService } from 'src/app/_services/web-socket.service';
+import Notification from 'src/app/_data/Notification';
@Component({
selector: 'app-notifications',
@@ -8,9 +9,16 @@ import { WebSocketService } from 'src/app/_services/web-socket.service';
})
export class NotificationsComponent implements OnInit {
- notifications?: any[];
+ notifications?: Notification[];
+ closed: boolean = false;
- constructor(private wsService: WebSocketService) { }
+ constructor(private wsService: WebSocketService) {
+ this.notifications = [
+ new Notification("Titanik (Preziveli)", "79768456867", 0.2),
+ new Notification("Test Prediktor 1", "56758768678", 0.4),
+ new Notification("Test Prediktor 2", "11344556425", 0.7)
+ ]
+ }
ngOnInit(): void {
// this.wsService.send('test');
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.css
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html
new file mode 100644
index 00000000..82365193
--- /dev/null
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.html
@@ -0,0 +1,7 @@
+<h2 mat-dialog-title class="text-muted">{{data.title}}</h2>
+<div mat-dialog-content class="mt-4" style="color: rgb(81, 76, 76);">
+ {{data.message}}
+</div>
+<div mat-dialog-actions class="d-flex justify-content-center mt-4">
+ <button mat-button cdkFocusInitial (click)="onOkClick()" style="background-color: lightgray;">OK</button>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.spec.ts b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.spec.ts
new file mode 100644
index 00000000..a93fc493
--- /dev/null
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AlertDialogComponent } from './alert-dialog.component';
+
+describe('AlertDialogComponent', () => {
+ let component: AlertDialogComponent;
+ let fixture: ComponentFixture<AlertDialogComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ AlertDialogComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(AlertDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/_modals/alert-dialog/alert-dialog.component.ts b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.ts
new file mode 100644
index 00000000..e15f3c6f
--- /dev/null
+++ b/frontend/src/app/_modals/alert-dialog/alert-dialog.component.ts
@@ -0,0 +1,28 @@
+import { Component, OnInit } from '@angular/core';
+import { Inject} from '@angular/core';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
+
+interface DialogData {
+ title: string;
+ message: string;
+}
+
+@Component({
+ selector: 'app-alert-dialog',
+ templateUrl: './alert-dialog.component.html',
+ styleUrls: ['./alert-dialog.component.css']
+})
+export class AlertDialogComponent {
+
+ constructor(
+ public dialogRef: MatDialogRef<AlertDialogComponent>,
+ @Inject(MAT_DIALOG_DATA) public data: DialogData,
+ //public dialog: MatDialog
+ ) {}
+
+ onOkClick(): void {
+ this.dialogRef.close();
+ }
+
+
+}
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.html b/frontend/src/app/_modals/login-modal/login-modal.component.html
index d7836848..03048155 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.html
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.html
@@ -3,7 +3,7 @@
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header" style="background-color: #003459;">
- <button id="closeButton" type="button" class="btn-close" style="background-color:white;" data-bs-dismiss="modal" aria-label="Close" (click)="resetData()"></button>
+ <button #closeButton type="button" class="btn-close" style="background-color:white;" data-bs-dismiss="modal" aria-label="Close" (click)="resetData()"></button>
</div>
<div class="modal-body px-5" style="color:#003459">
<h1 class="text-center mt-2 mb-4">Prijavite se</h1>
diff --git a/frontend/src/app/_modals/login-modal/login-modal.component.ts b/frontend/src/app/_modals/login-modal/login-modal.component.ts
index c86c269a..e1535a25 100644
--- a/frontend/src/app/_modals/login-modal/login-modal.component.ts
+++ b/frontend/src/app/_modals/login-modal/login-modal.component.ts
@@ -4,6 +4,7 @@ import { CookieService } from 'ngx-cookie-service';
import { AuthService } from 'src/app/_services/auth.service';
import { UserInfoService } from 'src/app/_services/user-info.service';
import shared from '../../Shared';
+import {AfterViewInit, ElementRef} from '@angular/core';
@Component({
selector: 'app-login-modal',
@@ -12,6 +13,8 @@ import shared from '../../Shared';
})
export class LoginModalComponent implements OnInit {
+ @ViewChild('closeButton') closeButton?: ElementRef;
+
username: string = '';
password: string = '';
@@ -38,7 +41,7 @@ export class LoginModalComponent implements OnInit {
}
else {
this.authService.authenticate(response);
- (<HTMLSelectElement>document.getElementById('closeButton')).click();
+ (<HTMLSelectElement>this.closeButton?.nativeElement).click();
this.userInfoService.getUserInfo().subscribe((response) => {
shared.photoId = response.photoId;
});
diff --git a/frontend/src/app/_modals/register-modal/register-modal.component.ts b/frontend/src/app/_modals/register-modal/register-modal.component.ts
index 13ef7eba..05888589 100644
--- a/frontend/src/app/_modals/register-modal/register-modal.component.ts
+++ b/frontend/src/app/_modals/register-modal/register-modal.component.ts
@@ -1,6 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { AuthService } from 'src/app/_services/auth.service';
import User from 'src/app/_data/User';
+import { DOCUMENT } from '@angular/common';
+import { Inject } from '@angular/core';
+import shared from 'src/app/Shared';
@Component({
selector: 'app-register-modal',
@@ -29,8 +32,11 @@ export class RegisterModalComponent implements OnInit {
pattEmail: RegExp = /^[a-zA-Z0-9]+([\.\-\+][a-zA-Z0-9]+)*\@([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}$/;
pattPassword: RegExp = /.{6,30}$/;
+ shared = shared;
+
constructor(
- private authService: AuthService
+ private authService: AuthService,
+ @Inject(DOCUMENT) document: Document
) { }
ngOnInit(): void {
@@ -149,11 +155,11 @@ export class RegisterModalComponent implements OnInit {
}, (error) => console.warn(error));
}
else if (response == 'Email Already Exists') {
- alert('Nalog sa unetim email-om već postoji!');
+ shared.openDialog("Greška!", "Nalog sa unetim email-om već postoji!");
(<HTMLSelectElement>document.getElementById('email')).focus();
}
else if (response == 'Username Already Exists') {
- alert('Nalog sa unetim korisničkim imenom već postoji!');
+ shared.openDialog("Greška!", "Nalog sa unetim korisničkim imenom već postoji!");
(<HTMLSelectElement>document.getElementById('username-register')).focus();
}
}
diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html
deleted file mode 100644
index 97b35b7a..00000000
--- a/frontend/src/app/_pages/add-model/add-model.component.html
+++ /dev/null
@@ -1,487 +0,0 @@
-<div id="header">
- <h1>Napravite svoj model veštačke neuronske mreže</h1>
-</div>
-
-<div id="wrapper">
- <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
- <div class="form-group row mt-3 mb-2 d-flex justify-content-center">
- <!--justify-content-center-->
- <h2 class="col-2"> Nov model: </h2>
- <div class="col-3">
- <label for="name" class="col-form-label">Naziv modela:</label>
- <input type="text" class="form-control" name="name" placeholder="Naziv..." [(ngModel)]="newModel.name">
- </div>
- <div class="col-5">
- <label for="desc" class="col-sm-2 col-form-label">Opis:</label>
- <div>
- <textarea class="form-control" name="desc" rows="3" [(ngModel)]="newModel.description"></textarea>
- </div>
- </div>
- <div class="col-2">
- <label for="dateCreated" class="col-form-label">Datum:</label> &nbsp;&nbsp;
- <input type="text" class="form-control-plaintext" id="dateCreated" placeholder="--/--/--"
- value="{{newModel.dateCreated | date: 'dd/MM/yyyy'}}" readonly>
- </div>
- </div>
-
- <div class="py-3 pr-5 justify-content-center">
-
- <div class="col-12 d-flex my-5">
- <h2 class="">Izvor podataka:</h2>
- <div class="col-1">
- </div>
- <button type="button" id="btnMyDataset" class="btn" (click)="viewMyDatasetsForm()"
- [ngClass]="{'btnType1': showMyDatasets, 'btnType2': !showMyDatasets}">
- Izaberite dataset iz kolekcije
- </button>
- <h3 class="mt-3 mx-3">ili</h3>
- <button type="button" id="btnNewDataset" class="btn" (click)="viewNewDatasetForm()"
- [ngClass]="{'btnType1': !showMyDatasets, 'btnType2': showMyDatasets}">
- 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|filter:term"
- [ngClass]="{'selectedDatasetClass': this.selectedDataset == dataset}">
- <app-item-dataset name="usersDataset" [dataset]="dataset"
- (click)="selectThisDataset(dataset);"></app-item-dataset>
- </li>
- </ul>
- </div>
- </div>
-
- <app-dataset-load [style]="(showMyDatasets)?'display:none;visibility:hidden;':''" id="dataset"
- (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>
- </div>
- </div>
-
- <!-- ULAZNE/IZLAZNE KOLONE -->
- <span id="selectInAndOuts"></span>
- <div
- *ngIf="selectedDataset && ((showMyDatasets && selectedDatasetLoaded) || (!showMyDatasets && datasetLoaded))">
- <!--postignuto da se kod newdataseta ucita tabela pa ulazi/izlazi. ostalo srediti to kod mydatasets(dopuna 2. uslova)-->
- <div class="row">
- <div class="col d-flex justify-content-center">
- <h3>Izaberite ulazne kolone:</h3>
- <div id="divInputs" class="form-check mt-2">
- <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]="this.selectedOutputColumnVal != item"
- [disabled]="this.selectedOutputColumnVal == item">&nbsp;
- <label class="form-check-label" for="cb_{{item}}">
- {{item}}
- </label>
- </div>
- </div>
- </div>
- <div class="col d-flex justify-content-left">
- <h3>Izaberite izlaznu kolonu:</h3>
- <div id="divOutputs" class="form-check mt-2">
- <br>
- <div *ngFor="let item of selectedDataset.header; let i = index">
- <input class="form-check-input" type="radio" value="{{item}}" id="rb_{{item}}" name="rbsNew"
- (change)="this.selectedOutputColumnVal = item">&nbsp;
- <label class="form-check-label" for="rb_{{item}}">
- {{item}}
- </label>
- </div>
- </div>
- </div>
-
-
- <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"
- class="form-check-input" value="deleteRows" name="fillMissing" id="delRows" checked
- data-bs-toggle="collapse" data-bs-target="#fillMissingCustom.show">
- <label for="delRows" class="form-check-label">Obriši sve
- redove sa nedostajućim vrednostima</label><br>
- <input type="radio" [(ngModel)]="newModel.nullValues" [value]="NullValueOptions.DeleteColumns"
- class="form-check-input" value="deleteCols" name="fillMissing" id="delCols"
- data-bs-toggle="collapse" data-bs-target="#fillMissingCustom.show">
- <label for="delCols" class="form-check-label">Obriši sve
- kolone sa nedostajućim vrednostima</label><br>
- <input type="radio" [(ngModel)]="newModel.nullValues" [value]="NullValueOptions.Replace"
- class="form-check-input" name="fillMissing" id="replace" data-bs-toggle="collapse"
- data-bs-target="#fillMissingCustom:not(.show)">
- <label for="replace" class="form-check-label">Izabraću
- vrednosti koje će da zamene nedostajuće vrednosti za svaku kolonu...</label><br><br>
- <div class="collapse" id="fillMissingCustom">
- <div>
- <label for="columnReplacers" class="form-label">Unesite zamenu za svaku kolonu:</label>
- <div id="columnReplacers">
- <!--Ulazne kolone - popunjavanje null vrednosti -->
- <div *ngFor="let column of selectedDataset.header; let i = index" class="my-3">
- <div *ngIf="getInputById('cb_'+column).checked" class="">
- <span class="w-20 mx-3">
- {{column}}&nbsp;<span class="small"
- style="color:gray;">({{calculateSumOfNullValuesInCol(column)}}
- null)</span>
- </span>
-
- <label *ngIf="calculateSumOfNullValuesInCol(column)==0"
- class="text-center form-control mx-3 text-secondary">Ova kolona nema
- nedostajućih
- vrednosti.</label>
-
- <div *ngIf="calculateSumOfNullValuesInCol(column)!=0"
- class="d-flex flex-row justify-content-end">
- <div class="flex-grow-3 mx-3 me-auto">
- <div class="input-group">
- <div class="input-group-prepend">
- <label [for]="'fillCol_'+column" class="form-control">
- Zameni
- <input type="radio" [id]="'fillCol_'+column"
- [name]="'delOp_'+column">
- </label>
- </div>
- <input type="text" class="form-control"
- [id]="'fillText_'+column"
- (keyup)="checkFillColRadio(column)"
- placeholder="Unesi vrednost...">
-
- <div class="input-group-append">
- <select [id]="'replaceOptions'+i"
- class="form-control btn-primary"
- *ngIf="isNumber(datasetFile[1][i])"
- (change)="replaceWithSelectedNumber($event);">
- <option
- *ngFor="let option of Object.keys(ReplaceWith); let optionName of Object.values(ReplaceWith)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- <select [id]="'replaceOptions'+i"
- class="form-control btn-outline-primary"
- *ngIf="!isNumber(datasetFile[1][i]) && calculateSumOfNullValuesInCol(column)!=0"
- (change)="replaceWithSelectedString($event);">
- <option
- *ngFor="let option of arrayColumn(datasetFile, i)"
- [value]="option">
- {{ option }}
- </option>
- </select>
- </div>
- </div>
- </div>
-
- <div class="flex-shrink-1 mx-3">
- <div class="input-group">
- <label class="form-control" [for]="'delCol_'+column">Izbriši
- kolonu
- <input type="radio" [id]="'delCol_'+column"
- [name]="'delOp_'+column"
- (change)="emptyFillTextInput(column)"></label>
- </div>
- </div>
-
- <div class="flex-shrink-1 mx-3">
- <div class="input-group">
- <label class="form-control" [for]="'delRows_'+column">Izbriši
- redove
- <input type="radio" [id]="'delRows_'+column"
- [name]="'delOp_'+column" checked
- (change)="emptyFillTextInput(column)"></label>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!--Izlazna kolona - popunjavanje null vrednosti -->
- <div *ngFor="let column of selectedDataset.header; let i = index" class="my-3">
- <!--moze bez for petlje (this.selectedOutputColumnVal je id), al ne moze ova fja array column onda-->
- <div class="input-group row" *ngIf="getInputById('rb_'+column).checked">
- <span class="input-group-text col-2 text-center">
- {{column}}&nbsp;<span class="small"
- style="color:gray;">({{calculateSumOfNullValuesInCol(column)}}
- null)</span>
- </span>
- <label *ngIf="calculateSumOfNullValuesInCol(column)==0"
- class="form-control">Ova kolona nema nedostajućih vrednosti.</label>
-
- <input *ngIf="calculateSumOfNullValuesInCol(column)!=0" type="radio"
- [id]="'fillCol_'+column" class="col-1 mt-2" [name]="'delOp_'+column">
- <!--OVDE SREDI IZGLED-->
- <select [id]="'replaceOptions'+i" class="form-control col-2"
- *ngIf="isNumber(datasetFile[1][i]) && calculateSumOfNullValuesInCol(column)!=0"
- (change)="replaceWithSelectedNumber($event);">
- <option
- *ngFor="let option of Object.keys(ReplaceWith); let optionName of Object.values(ReplaceWith)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- <select [id]="'replaceOptions'+i" class="form-control col-2"
- *ngIf="!isNumber(datasetFile[1][i]) && calculateSumOfNullValuesInCol(column)!=0"
- (change)="replaceWithSelectedString($event);">
- <option *ngFor="let option of arrayColumn(datasetFile, i)"
- [value]="option">
- {{ option }}
- </option>
- </select>
- <input *ngIf="calculateSumOfNullValuesInCol(column)!=0" type="text"
- class="form-control col-1" [id]="'fillText_'+column"
- (keyup)="checkFillColRadio(column)" placeholder="Unesi vrednost...">
-
- <label *ngIf="calculateSumOfNullValuesInCol(column)!=0"
- class="form-control col-2" [for]="'delCol_'+column">Izbriši kolonu
- <input type="radio" [id]="'delCol_'+column" [name]="'delOp_'+column"
- (change)="emptyFillTextInput(column)"></label>
- <label *ngIf="calculateSumOfNullValuesInCol(column)!=0"
- class="form-control col-2" [for]="'delRows_'+column">Izbriši redove
- <input type="radio" [id]="'delRows_'+column" [name]="'delOp_'+column"
- (change)="emptyFillTextInput(column)" checked></label>
- </div>
- </div>
-
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <h2 class="mt-5 mb-4">Parametri treniranja:</h2>
-
- <!--**********************************************************TIP*********************************************************-->
- <div>
- <div class="row p-2">
- <div class="col-1">
- </div>
- <div class="col-3">
- <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"
- (change)="filterOptions()">
- <option
- *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <!--******************************************************************************************************************-->
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="hiddenLayers" class="col-form-label">Broj skrivenih slojeva: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" class="form-control" name="hiddenLayers"
- [(ngModel)]="newModel.hiddenLayers"
- (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])">
- </div>
- </div>
-
- <div class="row p-2">
- <!--***********************************ENKODER*********************************************-->
-
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="encoding" class="col-form-label">Enkoding: </label>
- </div>
- <div class="col-2">
- <select id=encodingOptions class="form-control" name="encoding" [(ngModel)]="newModel.encoding">
- <option *ngFor="let option of Object.keys(Encoding); let optionName of Object.values(Encoding)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
-
- <!--***********************************BROJ NEURONA SKRIVENOG SLOJA*********************************************-->
-
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="hiddenLayerNeurons" class="col-form-label">Broj neurona skrivenih slojeva: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" class="form-control" name="hiddenLayerNeurons"
- [(ngModel)]="newModel.hiddenLayerNeurons">
- </div>
- </div>
- <!--***********************************OPTIMIZACIJA*********************************************-->
-
- <div class="row p-2">
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="optimizer" class="col-form-label">Optimizacija: </label>
- </div>
- <div class="col-2">
- <select id=optimizerOptions class="form-control" name="optimizer" [(ngModel)]="newModel.optimizer">
- <option
- *ngFor="let option of Object.keys(Optimizer); let optionName of Object.values(Optimizer)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="batchSize" class="col-form-label">Broj uzorka po iteraciji: </label>
- </div>
- <div class="col-1">
- <input type="number" min="1" class="form-control" name="batchSize" [(ngModel)]="newModel.batchSize">
- </div>
- </div>
- <div class="row p-2">
- <div class="col-1">
- </div>
- <div class="col-3">
- <label for="lossFunction" class="col-form-label">Funkcija obrade gubitka: </label>
- </div>
- <div class="col-2">
- <select id=lossFunctionOptions class="form-control" name="lossFunction"
- [(ngModel)]="newModel.lossFunction" aria-checked="true">
- <option
- *ngFor="let option of Object.keys(lossFunction); let optionName of Object.values(lossFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col-1"></div>
- <div class="col-3 mt-2">
- <label for="type" class="form-check-label">Nasumičan redosled podataka?</label>
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="newModel.randomOrder"
- type="checkbox" value="" checked>
- </div>
- </div>
- <!--************************************************************************************************* -->
- <div class="border m-3">
- <div class="row p-2 m-2">
- <div class="col-4">
- <label for="splitYesNo" class="form-check-label">
- <h3>Podela test skupa:&nbsp;&nbsp;
- <input id="splitYesNo" class="form-check-input" type="checkbox"
- [checked]="newModel.randomTestSet"
- (change)="newModel.randomTestSet = !newModel.randomTestSet">
- </h3>
- </label>
- </div>
- <div class="col-8">
- trening
- <mat-slider style="width: 85%;" min="10" max="90" step="10" value="10"
- name="randomTestSetDistribution" thumbLabel [disabled]="!newModel.randomTestSet"
- [(ngModel)]="tempTestSetDistribution">
- </mat-slider>
- test
- </div>
- </div>
-
- <div class="row p-2 mx-2">
- <div class="col-4">
- <label for="percentage" class="form-label">Procenat podataka koji se uzima za trening
- skup:</label>
- </div>
- <div class="col-2">
- <input id="percentage" type="number" class="form-control" min="10" max="90" step="10" value="90"
- [(ngModel)]="tempTestSetDistribution" [disabled]="!newModel.randomTestSet">
- </div>
- </div>
- </div>
-
- <!--***********************************AKTIVACIONE FUNKCIJE*********************************************-->
- <h3>Aktivacione funkcije:</h3>
-
- <div class="row p-2 m-2" style="align-self: center;">
- <div class="col-3">
- <label for="hiddenLayerActivationFunction" class="col-form-label"
- style="text-align: center;">Funkcija aktivacije skrivenih
- slojeva:</label>
- </div>
- <div class="col-3">
- <div *ngFor="let item of [].constructor(newModel.hiddenLayers); let i = index">
- <div class="input-group mb-2">
- <div class="input-group-prepend">
- <span class="input-group-text">#{{i+1}}</span>
- </div>
- <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>
- <div class="col-3">
- <label for="outputLayerActivationFunction" class="col-form-label"
- style="text-align: center;">Funkcija aktivacije izlaznog
- sloja:</label>
- </div>
- <div class="col-3">
- <select id=outputLayerActivationFunctionOptions class="form-control"
- name="outputLayerActivationFunction" [(ngModel)]="newModel.outputLayerActivationFunction">
- <option
- *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)"
- [value]="option">
- {{ optionName }}
- </option>
- </select>
- </div>
- <div class="col">
- </div>
- </div>
- </div>
-
- <br><br>
- <!--**********************************************METRIKE ZA KOMPAJLER I GRAFIKE***********************************************-->
-
- <hr>
- <div class="form-check form-check-inline overflow-auto " style="width: max-content;">
- <h3>Izaberite metrike:</h3>
- <div id="divMetricsinput">
-
- <div *ngFor="let option of Object.keys(metrics); let optionName of Object.values(metrics) "
- class="form-check form-check-inline">
-
- <input name="cbmetrics" class="form-check-input" type="checkbox" value="{{option}}"
- id="metrics_{{option}}" style="float: left;">
- <label class="form-check-label" for="metrics_{{option}}" for="inlineCheckbox2">
- {{optionName}}
- </label>
- </div>
- </div>
- </div>
- <!--<app-annvisual [model]="newModel"></app-annvisual>-->
- <div class="form-group row mt-5 mb-3">
- <div class="col"></div>
- <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" style="background-color:#003459; color:white;"
- (click)="trainModel();">Treniraj model</button>
- <div class="col"></div>
- </div>
-
- <div class="m-3" *ngIf="trainingResult">
- <h2>Rezultati treniranja</h2>
- <p>
- {{trainingResult}}
- </p>
- </div>
- </div>
-</div>
-
-<!--<button
- (click)="calculateSumOfNullValuesInCol('Embarked'); calculateMeanColValue('Age');calculateMedianColValue('Age'); getNullValuesReplacersArray();">DUGME</button>--> \ No newline at end of file
diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts
deleted file mode 100644
index 2121dc3b..00000000
--- a/frontend/src/app/_pages/add-model/add-model.component.ts
+++ /dev/null
@@ -1,510 +0,0 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
-import Model, { LossFunctionBinaryClassification, LossFunctionMultiClassification, LossFunctionRegression, NullValReplacer, ReplaceWith } from 'src/app/_data/Model';
-import { ProblemType, Encoding, ActivationFunction, LossFunction, Optimizer, NullValueOptions, Metrics, MetricsRegression, MetricsBinaryClassification, MetricsMultiClassification } 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';
-import Dataset from 'src/app/_data/Dataset';
-import { DatatableComponent } from 'src/app/_elements/datatable/datatable.component';
-import { DatasetsService } from 'src/app/_services/datasets.service';
-import { NgxCsvParser } from 'ngx-csv-parser';
-import { CsvParseService } from 'src/app/_services/csv-parse.service';
-
-
-@Component({
- selector: 'app-add-model',
- templateUrl: './add-model.component.html',
- styleUrls: ['./add-model.component.css']
-})
-export class AddModelComponent implements OnInit {
-
- @ViewChild(DatasetLoadComponent) datasetLoadComponent?: DatasetLoadComponent;
- @ViewChild(DatatableComponent) datatable?: DatatableComponent;
- datasetLoaded: boolean = false;
- selectedDatasetLoaded: boolean = false;
-
- newModel: Model;
-
- ProblemType = ProblemType;
- Encoding = Encoding;
- ActivationFunction = ActivationFunction;
- metrics: any = Metrics;
- LossFunction = LossFunction;
- lossFunction: any = LossFunction;
- Optimizer = Optimizer;
- NullValueOptions = NullValueOptions;
- ReplaceWith = ReplaceWith;
- Object = Object;
- document = document;
- shared = shared;
-
- selectedOutputColumnVal: string = '';
-
- showMyDatasets: boolean = true;
- myDatasets?: Dataset[];
- existingDatasetSelected: boolean = false;
- selectedDataset?: Dataset;
- otherDataset?: Dataset;
- otherDatasetFile?: any[];
- datasetFile?: any[];
- datasetHasHeader?: boolean = true;
-
- tempTestSetDistribution: number = 90;
-
- //accepted: Boolean;
- term: string = "";
-
- selectedProblemType: string = '';
- selectedMetrics = [];
-
- trainingResult: string | undefined;
-
- constructor(private models: ModelsService, private datasets: DatasetsService, private csv: CsvParseService) {
- this.newModel = new Model();
-
- this.datasets.getMyDatasets().subscribe((datasets) => {
- this.myDatasets = datasets;
- });
- }
-
- ngOnInit(): void {
- (<HTMLInputElement>document.getElementById("btnMyDataset")).focus();
- }
-
-
- viewMyDatasetsForm() {
- this.showMyDatasets = true;
- this.resetSelectedDataset();
- //this.datasetLoaded = false;
- this.resetCbsAndRbs();
- }
- viewNewDatasetForm() {
- this.showMyDatasets = false;
- this.resetSelectedDataset();
- this.resetCbsAndRbs();
- }
-
- addModel() {
- if (!this.showMyDatasets)
- this.saveModelWithNewDataset(_ => { console.log('MODEL ADDED (with new dataset).') });
- else
- this.saveModelWithExistingDataset(_ => { console.log('MODEL ADDED (with existing dataset).') });
- }
-
- trainModel() {
- let saveFunc;
- this.trainingResult = undefined;
-
- 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);
- this.trainingResult = response;
- });
- })); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad
- }
-
- saveModelWithNewDataset(callback: ((arg0: any) => void)) {
-
- this.getCheckedInputCols();
- this.getCheckedOutputCol();
- this.getMetrics();
-
- 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.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;
-
- //da se doda taj dataset u listu postojecih, da bude izabran
- this.refreshMyDatasetList();
- this.showMyDatasets = true;
- this.selectThisDataset(dataset);
-
- this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10;
- this.tempTestSetDistribution = 90;
- this.newModel.username = shared.username;
-
- this.newModel.nullValuesReplacers = this.getNullValuesReplacersArray();
-
- this.models.addModel(this.newModel).subscribe((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
- }, (error) => {
- alert("Dataset sa unetim nazivom već postoji u Vašoj kolekciji.\nIzmenite naziv ili iskoristite postojeći dataset.");
- }); //kraj addDataset subscribe
- } //kraj treceg ifa
- }, (error) => {
- //alert("greska uploadData");
- }); //kraj uploadData subscribe
-
- } //kraj drugog ifa
- } //kraj prvog ifa
- }
-
- saveModelWithExistingDataset(callback: ((arg0: any) => void)): any {
- if (this.selectedDataset) { //dataset je izabran
- this.getCheckedInputCols();
- this.getCheckedOutputCol();
- this.getMetrics();
- if (this.validationInputsOutput()) {
- this.newModel.datasetId = this.selectedDataset._id;
-
- this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10;
- this.tempTestSetDistribution = 90;
- this.newModel.username = shared.username;
-
- this.newModel.nullValuesReplacers = this.getNullValuesReplacersArray();
-
- this.models.addModel(this.newModel).subscribe((response) => {
- callback(response);
- }, (error) => {
- alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom.");
- });
- }
- }
- else {
- alert("Molimo Vas da izaberete neki dataset iz kolekcije.");
- }
- }
-
- getCheckedInputCols() {
- this.newModel.inputColumns = [];
- let checkboxes: any;
-
- checkboxes = document.getElementsByName("cbsNew");
-
- for (let i = 0; i < checkboxes.length; i++) {
- let thatCb = <HTMLInputElement>checkboxes[i];
- if (thatCb.checked == true) // && thatCb.disabled == false ne treba nam ovo vise
- this.newModel.inputColumns.push(thatCb.value);
- }
- //console.log(this.checkedInputCols);
- }
- getCheckedOutputCol() {
- this.newModel.columnToPredict = '';
- let radiobuttons: any;
-
- radiobuttons = document.getElementsByName("rbsNew");
-
- for (let i = 0; i < radiobuttons.length; i++) {
- let thatRb = <HTMLInputElement>radiobuttons[i];
- if (thatRb.checked) {
- this.newModel.columnToPredict = thatRb.value;
- break;
- }
- }
- //console.log(this.checkedOutputCol);
- }
- validationInputsOutput(): boolean {
- if (this.newModel.inputColumns.length == 0 && this.newModel.columnToPredict == '') {
- alert("Molimo Vas da izaberete ulazne i izlazne kolone za mrežu.");
- return false;
- }
- else if (this.newModel.inputColumns.length == 0) {
- alert("Molimo Vas da izaberete ulaznu kolonu/kolone za mrežu.");
- return false;
- }
- else if (this.newModel.columnToPredict == '') {
- alert("Molimo Vas da izaberete izlaznu kolonu za mrežu.");
- return false;
- }
- for (let i = 0; i < this.newModel.inputColumns.length; i++) {
- if (this.newModel.inputColumns[i] == this.newModel.columnToPredict) {
- let colName = this.newModel.columnToPredict;
- alert("Izabrali ste istu kolonu (" + colName + ") kao ulaznu i izlaznu iz mreže. Korigujte izbor.");
- return false;
- }
- }
- return true;
- }
-
- selectThisDataset(dataset: Dataset) {
- this.selectedDataset = dataset;
- this.selectedDatasetLoaded = false;
- this.existingDatasetSelected = true;
- this.datasetHasHeader = this.selectedDataset.hasHeader;
-
- this.datasets.getDatasetFile(dataset.fileId).subscribe((file: string | undefined) => {
- if (file) {
- this.datasetFile = this.csv.csvToArray(file, (dataset.delimiter == "razmak") ? " " : (dataset.delimiter == "") ? "," : dataset.delimiter);
- /*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);
- this.resetCbsAndRbs();
- this.refreshThreeNullValueRadioOptions();
- this.selectedDatasetLoaded = true;
- this.scrollToNextForm();
- }
- });
- //this.datasetHasHeader = false;
- }
-
- scrollToNextForm() {
- (<HTMLSelectElement>document.getElementById("selectInAndOuts")).scrollIntoView({
- behavior: "smooth",
- block: "start",
- inline: "nearest"
- });
- }
-
- resetSelectedDataset(): boolean {
- const temp = this.selectedDataset;
- this.selectedDataset = this.otherDataset;
- this.otherDataset = temp;
- const tempFile = this.datasetFile;
- this.datasetFile = this.otherDatasetFile;
- this.otherDatasetFile = tempFile;
- return true;
- }
- resetCbsAndRbs(): boolean {
- this.uncheckRbs();
- this.checkAllCbs();
- return true;
- }
- checkAllCbs() {
- let checkboxes: any;
-
- checkboxes = document.getElementsByName("cbsNew");
- for (let i = 0; i < checkboxes.length; i++) {
- (<HTMLInputElement>checkboxes[i]).checked = true;
- (<HTMLInputElement>checkboxes[i]).disabled = false;
- }
- }
- uncheckRbs() {
- this.selectedOutputColumnVal = '';
- let radiobuttons: any;
-
- radiobuttons = document.getElementsByName("rbsNew");
- for (let i = 0; i < radiobuttons.length; i++)
- (<HTMLInputElement>radiobuttons[i]).checked = false;
- }
-
- refreshMyDatasetList() {
- this.datasets.getMyDatasets().subscribe((datasets) => {
- this.myDatasets = datasets;
- });
- }
-
- refreshThreeNullValueRadioOptions() {
- this.newModel.nullValues = NullValueOptions.DeleteRows;
- }
-
- isChecked(someId: string) { //proveri ako je element sa datim ID-em cek
- return (<HTMLInputElement>document.getElementById(someId)).checked;
- }
-
- isNumber(value: string | number): boolean {
- return ((value != null) &&
- (value !== '') &&
- !isNaN(Number(value.toString())));
- }
-
- findColIndexByName(colName: string): number {
- if (this.datasetFile)
- for (let i = 0; i < this.datasetFile[0].length; i++)
- if (colName === this.datasetFile[0][i])
- return i;
- return -1;
- }
- findColNameByIndex(index: number): string {
- if (this.datasetFile)
- if (this.datasetHasHeader && index < this.datasetFile[0].length)
- return this.datasetFile[0][index];
- return '';
- }
- emptyFillTextInput(colName: string) {
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = "";
- }
-
- checkFillColRadio(colName: string) {
- (<HTMLInputElement>document.getElementById("fillCol_" + colName)).checked = true;
- }
- calculateSumOfNullValuesInCol(colName: string): number {
- //console.log(this.datasetFile);
- if (this.datasetFile) {
- let colIndex = this.findColIndexByName(colName);
- let sumOfNulls = 0;
-
- let startValue = (this.datasetLoadComponent?.dataset.hasHeader) ? 1 : 0;
- for (let i = startValue; i < this.datasetFile.length; i++) {
- if (this.datasetFile[i][colIndex] == "" || this.datasetFile[i][colIndex] == undefined)
- ++sumOfNulls;
- }
- return sumOfNulls;
- }
- return -1;
- }
- calculateMeanColValue(colName: string): number {
- if (this.datasetFile) {
- let colIndex = this.findColIndexByName(colName);
- let sum = 0;
- let n = 0;
-
- let startValue = (this.datasetLoadComponent?.dataset.hasHeader) ? 1 : 0;
- for (let i = startValue; i < this.datasetFile.length; i++)
- if (this.datasetFile[i][colIndex] != '') {
- sum += Number(this.datasetFile[i][colIndex]);
- ++n;
- }
- console.log(sum / n);
- return (sum != 0) ? (sum / n) : 0;
- }
- return 0;
- }
- calculateMedianColValue(colName: string): number {
- if (this.datasetFile) {
- let array = [];
- let colIndex = this.findColIndexByName(colName);
-
- let startValue = (this.datasetHasHeader) ? 1 : 0;
- for (let i = startValue; i < this.datasetFile.length; i++)
- if (this.datasetFile[i][colIndex] != '')
- array.push(Number(this.datasetFile[i][colIndex]));
-
- array.sort();
- if (array.length % 2 == 0)
- return array[array.length / 2 - 1] / 2;
- else
- return array[(array.length - 1) / 2];
- }
- return 0;
- }
- replaceWithSelectedString(event: Event) {
- let value = (<HTMLInputElement>event.target).value;
- let colIndex = Number(((<HTMLSelectElement>event.target).id).split("replaceOptions")[1]);
- let colName = this.findColNameByIndex(colIndex);
-
- (<HTMLInputElement>document.getElementById("fillCol_" + colName)).checked = true;
-
- if (!this.datasetHasHeader)
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = value;
- else {
- if (value == colName)
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = "";
- else
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = value;
- }
- }
- replaceWithSelectedNumber(event: Event) {
- let option = (<HTMLInputElement>event.target).value;
- let colIndex = Number(((<HTMLSelectElement>event.target).id).split("replaceOptions")[1]);
- let colName = this.findColNameByIndex(colIndex);
-
- (<HTMLInputElement>document.getElementById("fillCol_" + colName)).checked = true;
-
- if (option == ReplaceWith.Mean)
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = this.calculateMeanColValue(colName).toString();
- else if (option == ReplaceWith.Median)
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = this.calculateMedianColValue(colName).toString();
- else if (option == ReplaceWith.None)
- (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = "";
- }
-
-
- getNullValuesReplacersArray(): NullValReplacer[] {
- let array: NullValReplacer[] = [];
-
- if (this.datasetFile) {
-
- if (this.newModel.nullValues == NullValueOptions.Replace) {
-
- for (let i = 0; i < this.datasetFile[0].length; i++) {
- let column = this.datasetFile[0][i];
-
- if (this.calculateSumOfNullValuesInCol(column) > 0) { //ako kolona nema null vrednosti, ne dodajemo je u niz
- if ((<HTMLInputElement>document.getElementById("delCol_" + column)).checked) {
- array.push({
- column: column,
- option: NullValueOptions.DeleteColumns,
- value: ""
- });
- }
- else if ((<HTMLInputElement>document.getElementById("delRows_" + column)).checked) {
- array.push({
- column: column,
- option: NullValueOptions.DeleteRows,
- value: ""
- });
- }
- else if (((<HTMLInputElement>document.getElementById("fillCol_" + column)).checked)) {
- array.push({
- column: column,
- option: NullValueOptions.Replace,
- value: (<HTMLInputElement>document.getElementById("fillText_" + column)).value
- });
- }
- }
- }
- }
- }
- //console.log(array);
- return array;
- }
-
- getInputById(id: string): HTMLInputElement {
- return document.getElementById(id) as HTMLInputElement;
- }
-
- arrayColumn = (arr: any[][], n: number) => [...this.dropEmptyString(new Set(arr.map(x => x[n])))];
-
- dropEmptyString(set: Set<any>): Set<string> {
- if (set.has(""))
- set.delete("");
- if (set.has(null))
- set.delete(null);
- if (set.has(undefined))
- set.delete(undefined);
- return set;
- }
-
- filterOptions() {
- switch (this.newModel.type) {
- case 'regresioni':
- this.lossFunction = LossFunctionRegression;
- this.metrics = MetricsRegression;
- break;
- case 'binarni-klasifikacioni':
- this.lossFunction = LossFunctionBinaryClassification;
- this.metrics = MetricsBinaryClassification;
- break;
- case 'multi-klasifikacioni':
- this.lossFunction = LossFunctionMultiClassification;
- this.metrics = MetricsMultiClassification;
- break;
- default:
- break;
- }
- }
-
- getMetrics() {
- this.newModel.metrics = [];
- let cb = document.getElementsByName("cbmetrics");
-
- for (let i = 0; i < cb.length; i++) {
- let chb = <HTMLInputElement>cb[i];
- if (chb.checked == true)
- this.newModel.metrics.push(chb.value);
- }
-
- }
-}
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
index a4ab6e2c..27e06884 100644
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
+++ b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.html
@@ -5,7 +5,9 @@
<div class="row mt-3 mb-2 d-flex justify-content-center">
<div class="col-sm-6" style="margin-bottom: 10px;">
+ <p class="glyphicon glyphicon-search"></p>
<input type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term">
+
</div>
<div class="row">
@@ -14,7 +16,7 @@
<div class="card-body">
<h3 class="card-title"><b>{{predictor.name}}</b></h3>
<p class="card-text">{{predictor.description}}</p>
- <a class="btn btn-primary" (click)="openPredictor(predictor._id)">Otvori</a>
+ <a class="btn btn-primary" (click)="openPredictor(predictor._id)">Iskoristi</a>
</div>
<div class="card-footer text-muted">
Kreirao: {{predictor.username}} <br>
diff --git a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
index 4f96fc36..891b3cab 100644
--- a/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
+++ b/frontend/src/app/_pages/browse-predictors/browse-predictors.component.ts
@@ -20,7 +20,7 @@ export class BrowsePredictorsComponent implements OnInit {
ngOnInit(): void {
}
openPredictor(id:string):void{
- this.router.navigateByUrl('/predict?id='+id);
+ this.router.navigate(['predict/'+id]);
};
}
diff --git a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
index b75decf2..fc146046 100644
--- a/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
+++ b/frontend/src/app/_pages/filter-datasets/filter-datasets.component.ts
@@ -4,6 +4,7 @@ import Dataset from 'src/app/_data/Dataset';
import {Router} from '@angular/router'
import { JwtHelperService } from '@auth0/angular-jwt';
import { CookieService } from 'ngx-cookie-service';
+import shared from 'src/app/Shared';
@Component({
selector: 'app-filter-datasets',
@@ -12,6 +13,7 @@ import { CookieService } from 'ngx-cookie-service';
})
export class FilterDatasetsComponent implements OnInit {
+ shared = shared;
publicDatasets?: Dataset[];
term: string = "";
constructor(private datasets: DatasetsService,private router:Router, private cookie: CookieService) {
@@ -37,11 +39,9 @@ export class FilterDatasetsComponent implements OnInit {
if(name!=null && name!="")
this.datasets.addDataset(newDataset).subscribe((response:string)=>{
console.log(response);
- alert("Uspenso ste dodali dataset sa imenom "+newDataset.name);
+ shared.openDialog("Obaveštenje", "Uspešno ste dodali dataset sa nazivom " + newDataset.name);
},(error)=>{
- alert("Vec imate dataset sa istim imenom molim vas unesite drugo ime");
-
-
+ shared.openDialog("Obaveštenje", "U svojoj kolekciji već imate dataset sa ovim imenom. Molimo Vas da unesete drugo ime.");
});
};
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.html b/frontend/src/app/_pages/my-datasets/my-datasets.component.html
index 623b9ac8..d996bf31 100644
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.html
+++ b/frontend/src/app/_pages/my-datasets/my-datasets.component.html
@@ -1,5 +1,34 @@
-<ul class="list-group my-2">
- <li class="list-group-item" *ngFor="let dataset of myDatasets">
- <app-item-dataset [dataset]="dataset"></app-item-dataset>
- </li>
-</ul> \ No newline at end of file
+<div id="wrapper">
+ <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
+ <div class="row mt-3 mb-2 d-flex justify-content-center">
+
+ <div class="col-sm-6" style="margin-bottom: 10px;">
+ </div>
+
+ <div class="row">
+ <div class="col-sm-4" style="margin-bottom: 10px;" *ngFor="let dataset of myDatasets">
+ <app-item-dataset [dataset]="dataset"></app-item-dataset>
+
+ <div class="panel-footer row"><!-- panel-footer -->
+ <div class="col-xs-6 text-center">
+ <div>
+ <button type="button" class="btn btn-default btn-lg" mat-raised-button color="primary" (click)="deleteThisDataset(dataset)">Obriši
+ <span class="glyphicon glyphicon-chevron-right"></span>
+ </button>
+ </div>
+ </div>
+ </div><!-- end panel-footer -->
+ </div>
+ </div>
+ <div class="text-center" *ngIf="this.myDatasets.length == 0" >
+ <h2>Nema rezultata</h2>
+ </div>
+ </div>
+
+ </div>
+
+
+
+
+
+ </div>
diff --git a/frontend/src/app/_pages/my-datasets/my-datasets.component.ts b/frontend/src/app/_pages/my-datasets/my-datasets.component.ts
index 13b0c47b..1551a3c8 100644
--- a/frontend/src/app/_pages/my-datasets/my-datasets.component.ts
+++ b/frontend/src/app/_pages/my-datasets/my-datasets.component.ts
@@ -1,5 +1,10 @@
import { Component, OnInit } from '@angular/core';
+import {Router} from '@angular/router';
+import { DatasetsService } from 'src/app/_services/datasets.service';
import Dataset from 'src/app/_data/Dataset';
+import { JwtHelperService } from '@auth0/angular-jwt';
+import { CookieService } from 'ngx-cookie-service';
+import shared from 'src/app/Shared';
@Component({
selector: 'app-my-datasets',
@@ -7,18 +12,54 @@ import Dataset from 'src/app/_data/Dataset';
styleUrls: ['./my-datasets.component.css']
})
export class MyDatasetsComponent implements OnInit {
+ myDatasets: Dataset[] = [];
- myDatasets?: Dataset[];
+ constructor(private datasetsS : DatasetsService) {
- constructor() {
- this.myDatasets = [
- new Dataset('Titanik', 'Opis titanik', ['K1', 'K2', 'K3', 'Ime', 'Preziveli']),
- new Dataset('Neki drugi set', 'opis', ['a', 'b', 'c']),
- new Dataset('Treci set', 'opis', ['a', 'b', 'c'])
- ];
+
+
+ }
+
+ ngOnInit(): void {
+
+ this.datasetsS.getMyDatasets().subscribe((response) => {
+ this.myDatasets = response;
+ }, (error) => {
+ if (error.error == "Dataset with...") {
+ shared.openDialog("Greska", "Niste dobro uneli nesto");
+ }
+ });
+ }
+
+/*
+ editModel(): void{
+ this.modelsS.editModel().subscribe(m => {
+ this.myModel = m;
+
+ })
}
+*/
+
+deleteThisDataset(dataset: Dataset): void{
+ console.log("OK");
+ this.datasetsS.deleteDataset(dataset).subscribe((response) => {
+ console.log("OBRISANO JE", response);
+ //na kraju uspesnog
+ this.getAllMyDatasets();
+ }, (error) =>{
+ if (error.error == "Dataset with name = {name} deleted") {
+ alert("Greška pri brisanju dataseta!");
+ }
+ });
+
+}
- ngOnInit(): void {
+ getAllMyDatasets(): void{
+ this.datasetsS.getMyDatasets().subscribe(m => {
+
+ this.myDatasets = m;
+ console.log(this.myDatasets);
+ });
}
}
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 ec6c83d5..4aebc1f2 100644
--- a/frontend/src/app/_pages/my-models/my-models.component.html
+++ b/frontend/src/app/_pages/my-models/my-models.component.html
@@ -13,7 +13,7 @@
<div class="col-xs-6 text-center">
<div>
<button type="button" class="btn btn-default btn-lg" (click)="deleteThisModel(model)" mat-raised-button color="primary">Koristi
- <span class="glyphicon glyphicon-chevron-left"></span>
+ <span class="glyphicon glyphicon-search"></span>
</button>
<button type="button" class="btn btn-default btn-lg" mat-raised-button color="primary" (click)="deleteThisModel(model)">Obriši
<span class="glyphicon glyphicon-chevron-right"></span>
diff --git a/frontend/src/app/_pages/my-models/my-models.component.ts b/frontend/src/app/_pages/my-models/my-models.component.ts
index bd6b0a2b..6086b1b1 100644
--- a/frontend/src/app/_pages/my-models/my-models.component.ts
+++ b/frontend/src/app/_pages/my-models/my-models.component.ts
@@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
+import shared from 'src/app/Shared';
import Model from 'src/app/_data/Model';
import { ModelsService } from 'src/app/_services/models.service';
@@ -38,7 +39,7 @@ deleteThisModel(model: Model): void{
this.getAllMyModels();
}, (error) =>{
if (error.error == "Model with name = {name} deleted") {
- alert("Greška pri brisanju modela!");
+ shared.openDialog("Obaveštenje", "Greška prilikom brisanja modela.");
}
});
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.html b/frontend/src/app/_pages/my-predictors/my-predictors.component.html
index d739f561..3746d35e 100644
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.html
+++ b/frontend/src/app/_pages/my-predictors/my-predictors.component.html
@@ -7,7 +7,7 @@
<app-item-predictor [predictor]="predictor"></app-item-predictor>
</div>
<div>
- <button (click)="delete()" mat-raised-button color="warn" style="min-width: 15rem;float: right" ><mat-icon>delete</mat-icon></button>
+ <button (click)="delete(predictor)" mat-raised-button color="warn" style="min-width: 15rem;float: right" ><mat-icon>delete</mat-icon></button>
</div>
</div>
diff --git a/frontend/src/app/_pages/my-predictors/my-predictors.component.ts b/frontend/src/app/_pages/my-predictors/my-predictors.component.ts
index 58daa44f..13cfdab2 100644
--- a/frontend/src/app/_pages/my-predictors/my-predictors.component.ts
+++ b/frontend/src/app/_pages/my-predictors/my-predictors.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import Predictor from 'src/app/_data/Predictor';
+import { PredictorsService } from 'src/app/_services/predictors.service';
@Component({
selector: 'app-my-predictors',
@@ -7,22 +8,38 @@ import Predictor from 'src/app/_data/Predictor';
styleUrls: ['./my-predictors.component.css']
})
export class MyPredictorsComponent implements OnInit {
- predictors: Predictor[];
- constructor() {
- this.predictors = [
- new Predictor('Titanik', 'Opis titanik', ['K1', 'K2', 'K3', 'Ime', 'Preziveli'],'Preziveli'),
- new Predictor('Neki drugi set', 'opis', ['a', 'b', 'c'],'c'),
- 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')];
+ predictors: Predictor[] = [];
+ constructor(private predictorsS : PredictorsService) {
}
ngOnInit(): void {
+ this.getAllMyPredictors();
+
}
- delete(){
- confirm("IZABRANI MODEL ĆE BITI IZBRISAN")
+ delete(predictor: Predictor){
+ if(window.confirm("IZABRANI MODEL ĆE BITI IZBRISAN"))
+ {
+ this.predictorsS.deletePredictor(predictor).subscribe((response) => {
+ console.log("OBRISANOOO JEE", response);
+ //na kraju uspesnog
+ this.getAllMyPredictors();
+ }, (error) =>{
+ if (error.error == "Predictor with name = {name} deleted") {
+ alert("Greška pri brisanju modela!");
+ }
+ });
+ }
+
}
-
+
+ getAllMyPredictors(): void{
+ this.predictorsS.getMyPredictors().subscribe(m => {
+
+ this.predictors = m;
+ console.log(this.predictors);
+ });
+ }
}
diff --git a/frontend/src/app/_pages/predict/predict.component.html b/frontend/src/app/_pages/predict/predict.component.html
index bf4d9a1e..13afa8e4 100644
--- a/frontend/src/app/_pages/predict/predict.component.html
+++ b/frontend/src/app/_pages/predict/predict.component.html
@@ -18,7 +18,24 @@
<div>
<label for="output" class="col-sm-5 col-form-label">Opis prediktora: <b>{{predictor.description}}</b></label>
</div>
+
+
+ </div>
+ <br>
+ <label for="type" class="form-check-label" ><b>Informacije o prediktoru</b></label>
+ <div class="col-5 mt-2">
+ <label for="type" class="form-check-label" >Prediktor {{predictor.isPublic?"je":"nije"}} javni.</label>
+ </div>
+ <div class="col-5 mt-2">
+ <label for="type" class="form-check-label" >Prediktor {{predictor.accessibleByLink?"je":"nije"}} dostupan za deljenje.</label>
</div>
+ <br>
+ <div class="col-2">
+ <label for="dateCreated" class="col-form-label">Datum:</label>
+ <input type="text" class="form-control-plaintext" id="dateCreated" placeholder="--/--/--"
+ value="{{predictor.dateCreated | date: 'dd/MM/yyyy'}}" readonly>
+ </div>
+
<br>
<div >
@@ -28,7 +45,7 @@
<div *ngIf="predictor" class="form-group row mt-3 mb-2 d-flex justify-content-left">
<div *ngFor="let input of predictor.inputs; let i = index">
<label for="{{input}}" class="col-sm-2 col-form-label"><b>{{input}}</b></label>
- <input name="{{input}}" type="text" [(ngModel)]="inputs[i]" >
+ <input name="{{input}}" type="text" [(ngModel)]="inputs[i].value" >
</div>
@@ -41,28 +58,7 @@
<div>
<label for="output" class="col-sm-2 col-form-label">Izlaz: <b>{{predictor.output}}</b></label>
</div>
- <br>
- <br>
-
- <div class="col-5 mt-2">
- <label for="type" class="form-check-label">Da li je prediktor javan?</label>
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="predictor.isPublic"
- type="checkbox" value="">
- </div>
- <div class="col-5 mt-2">
- <label for="type" class="form-check-label">Da li je dostupan za deljenje?</label>
- <input class="mx-3 form-check-input" type="checkbox" [(ngModel)]="predictor.accessibleByLink"
- type="checkbox" value="" >
- </div>
- <br>
- <div class="col-2">
- <label for="dateCreated" class="col-form-label">Datum:</label>
- <input type="text" class="form-control-plaintext" id="dateCreated" placeholder="--/--/--"
- value="{{predictor.dateCreated | date: 'dd/MM/yyyy'}}" readonly>
- </div>
-
- <br><br>
<div class="form-group row mt-5 mb-3">
<div class="col"></div>
<button class="btn btn-lg col-4" style="background-color:#003459; color:white;"
diff --git a/frontend/src/app/_pages/predict/predict.component.ts b/frontend/src/app/_pages/predict/predict.component.ts
index 71cf93ce..1c1c7425 100644
--- a/frontend/src/app/_pages/predict/predict.component.ts
+++ b/frontend/src/app/_pages/predict/predict.component.ts
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import Predictor from 'src/app/_data/Predictor';
import { PredictorsService } from 'src/app/_services/predictors.service';
+import shared from 'src/app/Shared';
@Component({
selector: 'app-predict',
@@ -10,7 +11,8 @@ import { PredictorsService } from 'src/app/_services/predictors.service';
})
export class PredictComponent implements OnInit {
- inputs : String[] = [];
+ inputs : Column[] = [];
+
predictor:Predictor;
constructor(private predictS : PredictorsService, private route: ActivatedRoute) {
@@ -22,6 +24,7 @@ export class PredictComponent implements OnInit {
this.predictS.getPredictor(url["id"]).subscribe(p => {
this.predictor = p;
+ this.predictor.inputs.forEach((p,index)=> this.inputs[index] = new Column(p, ""));
console.log(this.predictor);
})
});
@@ -29,9 +32,16 @@ export class PredictComponent implements OnInit {
usePredictor(): void{
this.predictS.usePredictor(this.predictor, this.inputs).subscribe(p => {
-
- alert("Prediktor je uspesno poslat na treniranje!");
+ shared.openDialog("Obaveštenje", "Prediktor je uspešno poslat na probu."); //pisalo je "na treniranje" ??
})
console.log(this.inputs);
}
}
+
+
+export class Column {
+ constructor(
+ public name : string,
+ public value : (number | string)){
+ }
+} \ No newline at end of file
diff --git a/frontend/src/app/_pages/profile/profile.component.ts b/frontend/src/app/_pages/profile/profile.component.ts
index 7a7796da..d055fad3 100644
--- a/frontend/src/app/_pages/profile/profile.component.ts
+++ b/frontend/src/app/_pages/profile/profile.component.ts
@@ -6,6 +6,7 @@ import { Router } from '@angular/router';
import { PICTURES } from 'src/app/_data/ProfilePictures';
import { Picture } from 'src/app/_data/ProfilePictures';
import shared from '../../Shared';
+import { share } from 'rxjs';
@Component({
@@ -15,8 +16,6 @@ import shared from '../../Shared';
})
export class ProfileComponent implements OnInit {
-
-
user: User = new User();
pictures: Picture[] = PICTURES;
@@ -90,18 +89,18 @@ export class ProfileComponent implements OnInit {
if (this.user.username != editedUser.username) { //promenio username, ide logout
this.user = editedUser;
this.resetInfo();
- alert("Nakon promene korisničkog imena, moraćete ponovo da se ulogujete.");
+ shared.openDialog("Obaveštenje", "Nakon promene korisničkog imena, moraćete ponovo da se ulogujete.");
this.authService.logOut();
this.router.navigate(['']);
return;
}
- alert("Podaci su uspešno promenjeni.");
+ shared.openDialog("Obaveštenje", "Podaci su uspešno promenjeni.");
this.user = editedUser;
console.log(this.user);
this.resetInfo();
}, (error: any) =>{
if (error.error == "Username already exists!") {
- alert("Ukucano korisničko ime je već zauzeto!\nIzaberite neko drugo.");
+ shared.openDialog("Obaveštenje", "Ukucano korisničko ime je već zauzeto! Izaberite neko drugo.");
//(<HTMLSelectElement>document.getElementById("inputUsername")).focus();
//poruka obavestenja ispod inputa
this.resetInfo();
@@ -131,7 +130,7 @@ export class ProfileComponent implements OnInit {
this.userInfoService.changeUserPassword(passwordArray).subscribe((response: any) => {
//console.log("PROMENIO LOZINKU");
this.resetNewPassInputs();
- alert("Nakon promene lozinke, moraćete ponovo da se ulogujete.");
+ shared.openDialog("Obaveštenje", "Nakon promene lozinke, moraćete ponovo da se ulogujete.");
this.authService.logOut();
this.router.navigate(['']);
}, (error: any) => {
@@ -142,7 +141,7 @@ export class ProfileComponent implements OnInit {
return;
}
else if (error.error == 'Identical password!') {
- alert("Stara i nova lozinka su identične.");
+ shared.openDialog("Obaveštenje", "Stara i nova lozinka su identične.");
this.resetNewPassInputs();
//(<HTMLSelectElement>document.getElementById("inputNewPassword")).focus();
return;
diff --git a/frontend/src/app/_services/datasets.service.ts b/frontend/src/app/_services/datasets.service.ts
index 0ff63828..cd901481 100644
--- a/frontend/src/app/_services/datasets.service.ts
+++ b/frontend/src/app/_services/datasets.service.ts
@@ -27,4 +27,12 @@ export class DatasetsService {
getDatasetFile(fileId: any): any {
return this.http.get(`${API_SETTINGS.apiURL}/file/download?id=${fileId}`, { headers: this.authService.authHeader(), responseType: 'text' });
}
+
+ editDataset(dataset: Dataset): Observable<Dataset> {
+ return this.http.put<Dataset>(`${API_SETTINGS.apiURL}/dataset/`, dataset, { headers: this.authService.authHeader() });
+ }
+
+ deleteDataset(dataset: Dataset) {
+ return this.http.delete(`${API_SETTINGS.apiURL}/dataset/` + dataset.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 54ae5694..844cd706 100644
--- a/frontend/src/app/_services/predictors.service.ts
+++ b/frontend/src/app/_services/predictors.service.ts
@@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { API_SETTINGS } from 'src/config';
import Predictor from '../_data/Predictor';
+import { Column } from '../_pages/predict/predict.component';
import { AuthService } from './auth.service';
@Injectable({
@@ -21,7 +22,15 @@ export class PredictorsService {
return this.http.get<Predictor>(`${API_SETTINGS.apiURL}/predictor/getpredictor/`+ id, { headers: this.authService.authHeader() });
}
- usePredictor(predictor: Predictor, inputs : String[]) {
+ usePredictor(predictor: Predictor, inputs : Column[]) {
return this.http.post(`${API_SETTINGS.apiURL}/predictor/usepredictor/` + predictor._id, inputs, { headers: this.authService.authHeader() });
}
+
+ deletePredictor(predictor: Predictor) {
+ return this.http.delete(`${API_SETTINGS.apiURL}/predictor/` + predictor.name, { headers: this.authService.authHeader(), responseType: "text" });
+ }
+
+ getMyPredictors(): Observable<Predictor[]> {
+ return this.http.get<Predictor[]>(`${API_SETTINGS.apiURL}/predictor/mypredictors`, { headers: this.authService.authHeader() });
+ }
}
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index fd827ac9..93431397 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuardService } from './_services/auth-guard.service';
-import { AddModelComponent } from './_pages/add-model/add-model.component';
import { HomeComponent } from './_pages/home/home.component';
import { MyDatasetsComponent } from './_pages/my-datasets/my-datasets.component';
import { MyModelsComponent } from './_pages/my-models/my-models.component';
@@ -13,10 +12,12 @@ import { SettingsComponent } from './_pages/settings/settings.component';
import { ProfileComponent } from './_pages/profile/profile.component';
import { PredictComponent } from './_pages/predict/predict.component';
import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-datasets.component';
+import { ExperimentComponent } from './experiment/experiment.component';
const routes: Routes = [
{ path: '', component: HomeComponent, data: { title: 'Početna strana' } },
- { path: 'add-model', component: AddModelComponent, data: { title: 'Dodaj model' } },
+ /*{ path: 'add-model', component: AddModelComponent, data: { title: 'Dodaj model' } },*/
+ { path: 'experiment', component: ExperimentComponent, data: { title: 'Dodaj model' } },
{ path: 'my-datasets', component: MyDatasetsComponent, canActivate: [AuthGuardService], data: { title: 'Moji izvori podataka' } },
{ path: 'my-models', component: MyModelsComponent, canActivate: [AuthGuardService], data: { title: 'Moji modeli' } },
{ path: 'my-predictors', component: MyPredictorsComponent, canActivate: [AuthGuardService], data: { title: 'Moji trenirani modeli' } },
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index d90de54d..c3a2ce7a 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -1,4 +1,4 @@
-import { NgModule } from '@angular/core';
+import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
@@ -11,7 +11,6 @@ import { Ng2SearchPipeModule } from 'ng2-search-filter';
import { AppComponent } from './app.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DatasetLoadComponent } from './_elements/dataset-load/dataset-load.component';
-import { AddModelComponent } from './_pages/add-model/add-model.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LoginModalComponent } from './_modals/login-modal/login-modal.component';
import { ReactiveFormsModule } from '@angular/forms';
@@ -39,12 +38,16 @@ import { FilterDatasetsComponent } from './_pages/filter-datasets/filter-dataset
import { ReactiveBackgroundComponent } from './_elements/reactive-background/reactive-background.component';
import { ItemModelComponent } from './_elements/item-model/item-model.component';
import { AnnvisualComponent } from './_elements/annvisual/annvisual.component';
+import { ExperimentComponent } from './experiment/experiment.component';
+import { LoadingComponent } from './_elements/loading/loading.component';
+import { ModelLoadComponent } from './_elements/model-load/model-load.component';
+import { AlertDialogComponent } from './_modals/alert-dialog/alert-dialog.component';
+import { AddNewDatasetComponent } from './_elements/add-new-dataset/add-new-dataset.component';
@NgModule({
declarations: [
AppComponent,
DatasetLoadComponent,
- AddModelComponent,
LoginModalComponent,
RegisterModalComponent,
HomeComponent,
@@ -67,7 +70,12 @@ import { AnnvisualComponent } from './_elements/annvisual/annvisual.component';
FilterDatasetsComponent,
ReactiveBackgroundComponent,
ItemModelComponent,
- AnnvisualComponent
+ AnnvisualComponent,
+ ExperimentComponent,
+ LoadingComponent,
+ ModelLoadComponent,
+ AlertDialogComponent,
+ AddNewDatasetComponent
],
imports: [
BrowserModule,
@@ -84,6 +92,8 @@ import { AnnvisualComponent } from './_elements/annvisual/annvisual.component';
Ng2SearchPipeModule,
],
providers: [],
- bootstrap: [AppComponent]
+ bootstrap: [AppComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ entryComponents: [AlertDialogComponent]
})
export class AppModule { }
diff --git a/frontend/src/app/_pages/add-model/add-model.component.css b/frontend/src/app/experiment/experiment.component.css
index 6d961287..ee4b0448 100644
--- a/frontend/src/app/_pages/add-model/add-model.component.css
+++ b/frontend/src/app/experiment/experiment.component.css
@@ -3,6 +3,7 @@
padding-top: 30px;
padding-bottom: 20px;
}
+
#header h1 {
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
text-align: center;
@@ -21,15 +22,18 @@
background-color: #003459;
color: white;
}
+
.btnType2 {
background-color: white;
color: #003459;
border-color: #003459;
}
+
.selectedDatasetClass {
/*border-color: 2px solid #003459;*/
background-color: lightblue;
}
+
ul li:hover {
background-color: lightblue;
} \ No newline at end of file
diff --git a/frontend/src/app/experiment/experiment.component.html b/frontend/src/app/experiment/experiment.component.html
new file mode 100644
index 00000000..8d2c86b3
--- /dev/null
+++ b/frontend/src/app/experiment/experiment.component.html
@@ -0,0 +1,201 @@
+<div id="header">
+ <h1>Napravite svoju veštačku neuronske mrežu</h1>
+</div>
+<div id="wrapper">
+ <div id="container" class="container p-5" style="background-color: white; min-height: 100%;">
+
+
+ <h2>1. Izvor podataka</h2>
+ <app-dataset-load></app-dataset-load>
+
+
+ <h2>2. Preprocesiranje</h2>
+ <h3>Biranje ulaznih i izlaznih kolona:</h3>
+ <div *ngIf="selectedDataset">
+ <div class="row">
+ <div class="col d-flex justify-content-center">
+ <h3>Izaberite ulazne kolone:</h3>
+ <div id="divInputs" class="form-check mt-2">
+ <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]="this.selectedOutputColumnVal != item"
+ [disabled]="this.selectedOutputColumnVal == item">&nbsp;
+ <label class="form-check-label" for="cb_{{item}}">
+ {{item}}
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="col d-flex justify-content-left">
+ <h3>Izaberite izlaznu kolonu:</h3>
+ <div id="divOutputs" class="form-check mt-2">
+ <br>
+ <div *ngFor="let item of selectedDataset.header; let i = index">
+ <input class="form-check-input" type="radio" value="{{item}}" id="rb_{{item}}" name="rbsNew"
+ (change)="this.selectedOutputColumnVal = item">&nbsp;
+ <label class="form-check-label" for="rb_{{item}}">
+ {{item}}
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <h3>Popunjavanje nedostajućih vrednosti:</h3>
+ <div class="form-check" *ngIf="selectedDataset">
+ <input type="radio" [(ngModel)]="experiment.nullValues" [value]="NullValueOptions.DeleteRows"
+ class="form-check-input" value="deleteRows" name="fillMissing" id="delRows" checked
+ data-bs-toggle="collapse" data-bs-target="#fillMissingCustom.show">
+ <label for="delRows" class="form-check-label">Obriši sve
+ redove sa nedostajućim vrednostima</label><br>
+ <input type="radio" [(ngModel)]="experiment.nullValues" [value]="NullValueOptions.DeleteColumns"
+ class="form-check-input" value="deleteCols" name="fillMissing" id="delCols" data-bs-toggle="collapse"
+ data-bs-target="#fillMissingCustom.show">
+ <label for="delCols" class="form-check-label">Obriši sve
+ kolone sa nedostajućim vrednostima</label><br>
+ <input type="radio" [(ngModel)]="experiment.nullValues" [value]="NullValueOptions.Replace"
+ class="form-check-input" name="fillMissing" id="replace" data-bs-toggle="collapse"
+ data-bs-target="#fillMissingCustom:not(.show)">
+ <label for="replace" class="form-check-label">Izabraću
+ vrednosti koje će da zamene nedostajuće vrednosti za svaku kolonu...</label><br><br>
+ <div class="collapse" id="fillMissingCustom">
+ <div>
+ <label for="columnReplacers" class="form-label">Unesite zamenu za svaku kolonu:</label>
+ <div id="columnReplacers">
+ <div *ngFor="let column of selectedDataset.columnInfo; let i = index" class="my-3">
+ <div *ngIf="getInputById('cb_'+column).checked" class="">
+ <span class="w-20 mx-3">
+ {{column.name}}&nbsp;<span class="small" style="color:gray;">(
+ <!--{{//column.numNulls}}-->
+ TODO BROJ null)
+ </span>
+ </span>
+
+ <label *ngIf="column.numNull <= 0" class="text-center form-control mx-3 text-secondary">
+ Ova kolona nema
+ nedostajućih
+ vrednosti.
+ </label>
+
+ <div *ngIf="column.numNull > 0" class="d-flex flex-row justify-content-end">
+ <!-- ngIf colummn.numNulls == 0 -->
+ <div class="flex-grow-3 mx-3 me-auto">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <label [for]="'fillCol_'+column.name" class="form-control">
+ Zameni
+ <input type="radio" [id]="'fillCol_'+column.name"
+ [name]="'delOp_'+column.name">
+ </label>
+ </div>
+ <input type="text" class="form-control" [id]="'fillText_'+column.name"
+ (keyup)="checkFillColRadio(column.name)"
+ placeholder="Unesi vrednost...">
+
+ <div class="input-group-append">
+ <select [id]="'replaceOptions'+i" class="form-control btn-primary"
+ *ngIf="column.isNumber" (change)="replace($event);">
+ <option
+ *ngFor="let option of Object.keys(ReplaceWith); let optionName of Object.values(ReplaceWith)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ <select [id]="'replaceOptions'+i"
+ class="form-control btn-outline-primary"
+ *ngIf="!column.isNumber && column.numNull > 0"
+ (change)="replace($event);">
+ <option *ngFor="let option of column.uniqueValues" [value]="option">
+ {{ option }}
+ </option>
+ </select>
+ </div>
+ </div>
+ </div>
+
+ <div class="flex-shrink-1 mx-3">
+ <div class="input-group">
+ <label class="form-control" [for]="'delCol_'+column.name">Izbriši
+ kolonu
+ <input type="radio" [id]="'delCol_'+column"
+ [name]="'delOp_'+column.name"
+ (change)="emptyFillTextInput(column.name)"></label>
+ </div>
+ </div>
+
+ <div class="flex-shrink-1 mx-3">
+ <div class="input-group">
+ <label class="form-control" [for]="'delRows_'+column.name">Izbriši
+ redove
+ <input type="radio" [id]="'delRows_'+column.name"
+ [name]="'delOp_'+column.name" checked
+ (change)="emptyFillTextInput(column.name)"></label>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div *ngFor="let column of selectedDataset.columnInfo; let i = index" class="my-3">
+ <div class="input-group row" *ngIf="getInputById('rb_'+column.name).checked">
+ <span class="input-group-text col-2 text-center">
+ {{column}}&nbsp;<span class="small" style="color:gray;">(br
+ null)</span>
+ </span>
+ <label *ngIf="true" class="form-control">Ova
+ kolona nema nedostajućih vrednosti.</label>
+
+ <input *ngIf="true" type="radio" [id]="'fillCol_'+column.name" class="col-1 mt-2"
+ [name]="'delOp_'+column.name">
+ <select [id]="'replaceOptions'+i" class="form-control col-2" *ngIf="column.isNumber"
+ (change)="replace($event);">
+ <option
+ *ngFor="let option of Object.keys(ReplaceWith); let optionName of Object.values(ReplaceWith)"
+ [value]="option">
+ {{ optionName }}
+ </option>
+ </select>
+ <select [id]="'replaceOptions'+i" class="form-control col-2" *ngIf="!column.isNumber"
+ (change)="replace($event);">
+ <option *ngFor="let option of []" [value]="option">
+ <!--/*arrayColumn(datasetFile, i)*/-->
+ {{ option }}
+ </option>
+ </select>
+ <input *ngIf="true" type="text" class="form-control col-1"
+ [id]="'fillText_'+column.name" (keyup)="checkFillColRadio(column.name)"
+ placeholder="Unesi vrednost...">
+
+ <label *ngIf="true" class="form-control col-2" [for]="'delCol_'+column" .name>Izbriši
+ kolonu
+ <input type="radio" [id]="'delCol_'+column.name" [name]="'delOp_'+column.name"
+ (change)="emptyFillTextInput(column.name)"></label>
+ <label *ngIf="true" class="form-control col-2" [for]="'delRows_'+column.name">Izbriši
+ redove
+ <input type="radio" [id]="'delRows_'+column.name" [name]="'delOp_'+column.name"
+ (change)="emptyFillTextInput(column.name)" checked></label>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+ <h2>3. Podešavanja mreže</h2>
+ <app-model-load></app-model-load>
+
+
+ <h2>4. Treniraj model</h2>
+ <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="trainModel();">Treniraj
+ model</button>
+ <h3>Rezultati treniranja</h3>
+ <div class="m-3" *ngIf="trainingResult">
+ <h2 class="my-2">Rezultati treniranja:</h2>
+ <p>
+ {{trainingResult}}
+ </p>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/frontend/src/app/experiment/experiment.component.spec.ts b/frontend/src/app/experiment/experiment.component.spec.ts
new file mode 100644
index 00000000..fd2bbd30
--- /dev/null
+++ b/frontend/src/app/experiment/experiment.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ExperimentComponent } from './experiment.component';
+
+describe('ExperimentComponent', () => {
+ let component: ExperimentComponent;
+ let fixture: ComponentFixture<ExperimentComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ExperimentComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ExperimentComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/frontend/src/app/experiment/experiment.component.ts b/frontend/src/app/experiment/experiment.component.ts
new file mode 100644
index 00000000..2309dcd7
--- /dev/null
+++ b/frontend/src/app/experiment/experiment.component.ts
@@ -0,0 +1,118 @@
+import { Component, OnInit } from '@angular/core';
+import Experiment, { NullValReplacer, NullValueOptions, ReplaceWith } from '../_data/Experiment';
+import Model from '../_data/Model';
+import Dataset from '../_data/Dataset';
+import { ModelsService } from '../_services/models.service';
+import Shared from '../Shared';
+
+@Component({
+ selector: 'app-experiment',
+ templateUrl: './experiment.component.html',
+ styleUrls: ['./experiment.component.css']
+})
+export class ExperimentComponent implements OnInit {
+
+ experiment: Experiment = new Experiment();
+ selectedModel?: Model;
+ selectedDataset?: Dataset;
+ trainingResult: any; // any za sad, promeni kasnije
+
+ NullValueOptions = NullValueOptions;
+ ReplaceWith = ReplaceWith;
+ Object = Object;
+
+ selectedOutputColumnVal: string = '';
+
+ constructor(private models: ModelsService) { }
+
+ ngOnInit(): void {
+ }
+
+ getInputById(id: string): HTMLInputElement {
+ return document.getElementById(id) as HTMLInputElement;
+ }
+
+ arrayColumn = (arr: any[][], n: number) => [...this.dropEmptyString(new Set(arr.map(x => x[n])))];
+
+ dropEmptyString(set: Set<any>): Set<string> {
+ if (set.has(""))
+ set.delete("");
+ if (set.has(null))
+ set.delete(null);
+ if (set.has(undefined))
+ set.delete(undefined);
+ return set;
+ }
+
+ emptyFillTextInput(colName: string) {
+ (<HTMLInputElement>document.getElementById("fillText_" + colName)).value = "";
+ }
+
+ checkFillColRadio(colName: string) {
+ (<HTMLInputElement>document.getElementById("fillCol_" + colName)).checked = true;
+ }
+
+ replace(event: Event) {
+ let option = (<HTMLInputElement>event.target).value;
+ // TODO
+ }
+
+ getNullValuesReplacersArray()/*: NullValReplacer[]*/ {
+ let array: NullValReplacer[] = [];
+
+ // TODO ispravi
+ /*if (this.datasetFile) {
+
+ if (this.newModel.nullValues == NullValueOptions.Replace) {
+
+ for (let i = 0; i < this.datasetFile[0].length; i++) {
+ let column = this.datasetFile[0][i];
+
+ if (this.calculateSumOfNullValuesInCol(column) > 0) { //ako kolona nema null vrednosti, ne dodajemo je u niz
+ if ((<HTMLInputElement>document.getElementById("delCol_" + column)).checked) {
+ array.push({
+ column: column,
+ option: NullValueOptions.DeleteColumns,
+ value: ""
+ });
+ }
+ else if ((<HTMLInputElement>document.getElementById("delRows_" + column)).checked) {
+ array.push({
+ column: column,
+ option: NullValueOptions.DeleteRows,
+ value: ""
+ });
+ }
+ else if (((<HTMLInputElement>document.getElementById("fillCol_" + column)).checked)) {
+ array.push({
+ column: column,
+ option: NullValueOptions.Replace,
+ value: (<HTMLInputElement>document.getElementById("fillText_" + column)).value
+ });
+ }
+ }
+ }
+ }
+ }
+ //console.log(array);
+ return array;*/
+ }
+
+ trainModel() {
+ this.trainingResult = undefined;
+ console.log('Training model...', this.selectedModel);
+ if (!this.selectedDataset) {
+ Shared.openDialog('Greška', 'Izvor podataka nije izabran!');
+ return;
+ }
+ // TODO proveri nullValues
+ if (!this.selectedModel) {
+ Shared.openDialog('Greška', 'Model nije izabran!');
+ return;
+ }
+ this.models.trainModel(this.selectedModel).subscribe((response: any) => {
+ console.log('Train model complete!', response);
+ this.trainingResult = response;
+ });
+ }
+}
diff --git a/frontend/src/app/material.module.ts b/frontend/src/app/material.module.ts
index e85419ee..d16cef3d 100644
--- a/frontend/src/app/material.module.ts
+++ b/frontend/src/app/material.module.ts
@@ -1,18 +1,21 @@
import { NgModule } from '@angular/core';
-
+import { CommonModule } from '@angular/common';
import { MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
@NgModule({
exports: [
+ CommonModule,
MatDialogModule,
MatButtonModule,
MatFormFieldModule,
MatInputModule,
- MatCheckboxModule
+ MatCheckboxModule,
+ MatIconModule
]
})
export class MaterialModule {} \ No newline at end of file