diff options
Diffstat (limited to 'frontend')
11 files changed, 130 insertions, 90 deletions
diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index 48418d51..32247bbd 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -23,12 +23,14 @@ export default class Model { public hiddenLayerNeurons: number = 1, public hiddenLayers: number = 1, public batchSize: number = 5, - public hiddenLayerActivationFunction = [], + public hiddenLayerActivationFunctions: string[] = ['sigmoid'], //public inputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid, public outputLayerActivationFunction: ActivationFunction = ActivationFunction.Sigmoid, public username: string = '', public nullValues: NullValueOptions = NullValueOptions.DeleteRows, - public nullValuesReplacers = [] + public nullValuesReplacers = [], + public metrics: Metric[] = [], // TODO add to add-model form + public epochs: number = 5 // TODO add to add-model form ) { } } @@ -111,4 +113,11 @@ export enum ReplaceWith { None = 'Popuni...', Mean = 'Srednja vrednost', Median = 'Medijana' +} + +export enum Metric { + MSE = 'mse', + MAE = 'mae', + RMSE = 'rmse' + //... }
\ No newline at end of file diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.css b/frontend/src/app/_elements/annvisual/annvisual.component.css index e69de29b..857a3390 100644 --- a/frontend/src/app/_elements/annvisual/annvisual.component.css +++ b/frontend/src/app/_elements/annvisual/annvisual.component.css @@ -0,0 +1,4 @@ +#graph{ + width: 100%; + text-align: center; +}
\ No newline at end of file diff --git a/frontend/src/app/_elements/annvisual/annvisual.component.html b/frontend/src/app/_elements/annvisual/annvisual.component.html index 6dd3b3ae..f23022de 100644 --- a/frontend/src/app/_elements/annvisual/annvisual.component.html +++ b/frontend/src/app/_elements/annvisual/annvisual.component.html @@ -1,5 +1,5 @@ <div style="text-align: center; width: 100%;" > - <button (click)="d3()">Prikaz veštačke neuronske mreže</button> - <div id="graph"></div> + <button (click)="d3()" mat-raised-button color="primary">Prikaz veštačke neuronske mreže</button> + <div id="graph" align-items-center ></div> </div> diff --git a/frontend/src/app/_elements/reactive-background/reactive-background.component.ts b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts index 95b61b1b..8294a8a5 100644 --- a/frontend/src/app/_elements/reactive-background/reactive-background.component.ts +++ b/frontend/src/app/_elements/reactive-background/reactive-background.component.ts @@ -7,18 +7,19 @@ import { Component, OnInit } from '@angular/core'; }) export class ReactiveBackgroundComponent implements OnInit { - numPoints: number = 400; + numPoints: number = 450; speed: number = 0.001; // 0-1 rotateInterval: number = 1000; maxSize: number = 6; - minDistance: number = 0.1; //0-1 - cursorDistance: number = 0.15; + minDistance: number = 0.07; //0-1 + cursorDistance: number = 0.07; private points: Point[] = []; private width = 200; private height = 200; + private ratio = 1; private canvas?: HTMLCanvasElement; private ctx?: CanvasRenderingContext2D; @@ -110,6 +111,7 @@ export class ReactiveBackgroundComponent implements OnInit { resize() { this.width = window.innerWidth; this.height = window.innerHeight; + this.ratio = this.width / this.height; if (this.canvas) { this.canvas.width = this.width; @@ -149,7 +151,7 @@ export class ReactiveBackgroundComponent implements OnInit { } distance(x1: number, y1: number, x2: number, y2: number): number { - return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); + return Math.sqrt(((x2 - x1) ** 2) + ((y2 / this.ratio - y1 / this.ratio) ** 2)); } } diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html index 9dde9afe..662d34de 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.html +++ b/frontend/src/app/_pages/add-model/add-model.component.html @@ -40,7 +40,9 @@ Dodajte novi dataset </button> </div> - <input type="text" class="form-control" placeholder="Pretraga" [(ngModel)]="term"> + <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"> @@ -71,7 +73,8 @@ <br> <div *ngFor="let item of selectedDataset.header; let i = index"> <input class="form-check-input" type="checkbox" value="{{item}}" id="cb_{{item}}" - name="cbsNew" [checked] = "this.selectedOutputColumnVal != item" [disabled]="this.selectedOutputColumnVal == item"> + name="cbsNew" [checked]="this.selectedOutputColumnVal != item" + [disabled]="this.selectedOutputColumnVal == item"> <label class="form-check-label" for="cb_{{item}}"> {{item}} </label> @@ -93,7 +96,7 @@ </div> - <div class="my-2" *ngIf="datasetFile"> + <div class="mt-5" *ngIf="datasetFile"> <h2>Popunjavanje nedostajućih vrednosti:</h2> <div class="form-check"> <input type="radio" [(ngModel)]="newModel.nullValues" [value]="NullValueOptions.DeleteRows" @@ -163,7 +166,8 @@ </div> <div class="col-2"> <select id=typeOptions class="form-control" name="type" [(ngModel)]="newModel.type"> - <option *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" + <option + *ngFor="let option of Object.keys(ProblemType); let optionName of Object.values(ProblemType)" [value]="option"> {{ optionName }} </option> @@ -176,7 +180,8 @@ </div> <div class="col-1"> <input type="number" min="1" class="form-control" name="hiddenLayers" - [(ngModel)]="newModel.hiddenLayers"> + [(ngModel)]="newModel.hiddenLayers" + (change)="newModel.hiddenLayerActivationFunctions = [].constructor(newModel.hiddenLayers).fill(newModel.hiddenLayerActivationFunctions[0])"> </div> </div> @@ -258,56 +263,36 @@ </div> <div class="row p-2"> - - <!-- <div class="col-1"> - </div> + <div class="col-3"></div> <div class="col-3"> - <label for="inputLayerActivationFunction" class="col-form-label">Funkcija aktivacije ulaznog - sloja:</label> + <label for="hiddenLayerActivationFunction" class="col-form-label">Funkcija aktivacije skrivenih + slojeva:</label> </div> - - <div class="col-2"> - <select id=inputLayerActivationFunctionOptions class="form-control" - name="inputLayerActivationFunction" [(ngModel)]="newModel.inputLayerActivationFunction"> - <option - *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" - [value]="option"> - {{ optionName }} - </option> - </select> + <div class="col-3"> + <div *ngFor="let item of [].constructor(newModel.hiddenLayers); let i = index"> + <select [id]="'hiddenLayerActivationFunctionOption_'+i" class="form-control" + [(ngModel)]="newModel.hiddenLayerActivationFunctions[i]"> + <option + *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" + [value]="option"> + {{ optionName }} + </option> + </select> + </div> </div> + <div class="col-3"></div> + </div> + + <div class="row p-2"> <div class="col-1"> </div> - --> - - <div class="col-5"> + <div class="col-3"> <label for="splitYesNo" class="form-check-label">Podela test skupa: <input id="splitYesNo" class="form-check-input" type="checkbox" [checked]="newModel.randomTestSet" (change)="newModel.randomTestSet = !newModel.randomTestSet"> </label> </div> - <div class="col"> - </div> - </div> - - <div class="row p-2"> - <div class="col-1"> - </div> - <div class="col-3"> - <label for="hiddenLayerActivationFunction" class="col-form-label">Funkcija aktivacije skrivenih - slojeva:</label> - </div> - <div class="col-2"> - <select id=hiddenLayerActivationFunctionOptions class="form-control" - name="hiddenLayerActivationFunction" [(ngModel)]="newModel.hiddenLayerActivationFunction"> - <option - *ngFor="let option of Object.keys(ActivationFunction); let optionName of Object.values(ActivationFunction)" - [value]="option"> - {{ optionName }} - </option> - </select> - </div> <div class="col-1"> </div> <div class="col-2"> @@ -357,7 +342,7 @@ <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="addModel();">Sačuvaj model</button> <div class="col"></div> - <button class="btn btn-lg col-4 disabled" style="background-color:#003459; color:white;" + <button class="btn btn-lg col-4" style="background-color:#003459; color:white;" (click)="trainModel();">Treniraj model</button> <div class="col"></div> </div> diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts index 37672d0a..77a506d5 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.ts +++ b/frontend/src/app/_pages/add-model/add-model.component.ts @@ -53,7 +53,7 @@ export class AddModelComponent implements OnInit { constructor(private models: ModelsService, private datasets: DatasetsService, private csv: CsvParseService) { this.newModel = new Model(); - this.models.getMyDatasets().subscribe((datasets) => { + this.datasets.getMyDatasets().subscribe((datasets) => { this.myDatasets = datasets; }); } @@ -76,19 +76,28 @@ export class AddModelComponent implements OnInit { addModel() { if (!this.showMyDatasets) - this.saveModelWithNewDataset(); + this.saveModelWithNewDataset(_ => { console.log('MODEL ADDED (with new dataset).') }); else - this.saveModelWithExistingDataset(); + this.saveModelWithExistingDataset(_ => { console.log('MODEL ADDED (with existing dataset).') }); } trainModel() { - this.saveModelWithNewDataset().subscribe((modelId: any) => { - if (modelId) - this.models.trainModel(modelId); - }); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad + let saveFunc; + + if (!this.showMyDatasets) + saveFunc = (x: (arg0: any) => void) => { this.saveModelWithNewDataset(x) }; + else + saveFunc = (x: (arg0: any) => void) => { this.saveModelWithExistingDataset(x) }; + + saveFunc(((model: any) => { + console.log('Saved, training model...', model); + this.models.trainModel(model).subscribe(response => { + console.log('Train model complete!', response); + }); + })); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad } - saveModelWithNewDataset(): any { + saveModelWithNewDataset(callback: ((arg0: any) => void)) { this.getCheckedInputCols(); this.getCheckedOutputCol(); @@ -103,7 +112,7 @@ export class AddModelComponent implements OnInit { this.datasetLoadComponent.dataset.fileId = file._id; this.datasetLoadComponent.dataset.username = shared.username; - this.models.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => { + this.datasets.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => { console.log('ADD MODEL: STEP 3 - ADD MODEL WITH DATASET ID ', dataset._id); this.newModel.datasetId = dataset._id; @@ -117,7 +126,7 @@ export class AddModelComponent implements OnInit { this.newModel.username = shared.username; this.models.addModel(this.newModel).subscribe((response) => { - console.log('ADD MODEL: DONE! REPLY:\n', response); + callback(response); }, (error) => { alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); }); //kraj addModel subscribe @@ -133,8 +142,7 @@ export class AddModelComponent implements OnInit { } //kraj prvog ifa } - saveModelWithExistingDataset(): any { - + saveModelWithExistingDataset(callback: ((arg0: any) => void)): any { if (this.selectedDataset) { //dataset je izabran this.getCheckedInputCols(); this.getCheckedOutputCol(); @@ -147,7 +155,7 @@ export class AddModelComponent implements OnInit { this.newModel.username = shared.username; this.models.addModel(this.newModel).subscribe((response) => { - console.log('ADD MODEL: DONE! REPLY:\n', response); + callback(response); }, (error) => { alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); }); @@ -226,7 +234,7 @@ export class AddModelComponent implements OnInit { 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 + else break; //nema potrebe dalje } console.log(this.datasetFile); @@ -279,7 +287,7 @@ export class AddModelComponent implements OnInit { } refreshMyDatasetList() { - this.models.getMyDatasets().subscribe((datasets) => { + this.datasets.getMyDatasets().subscribe((datasets) => { this.myDatasets = datasets; }); } diff --git a/frontend/src/app/_services/auth.service.ts b/frontend/src/app/_services/auth.service.ts index 449b8802..ccfbe15f 100644 --- a/frontend/src/app/_services/auth.service.ts +++ b/frontend/src/app/_services/auth.service.ts @@ -24,10 +24,16 @@ export class AuthService { return this.http.post(`${API_SETTINGS.apiURL}/auth/register`, { ...user }, { responseType: 'text' }); } + getGuestToken(){ + return this.http.post(`${API_SETTINGS.apiURL}/auth/guestToken`, {}, { responseType: 'text' }); + } + isAuthenticated(): boolean { if (this.cookie.check('token')) { var token = this.cookie.get('token'); - return !jwtHelper.isTokenExpired(token); + var property=jwtHelper.decodeToken(this.cookie.get('token')); + var username=property['name']; + return !jwtHelper.isTokenExpired(token) && username!=""; } return false; } @@ -41,12 +47,30 @@ export class AuthService { if (!exp) { exp = new Date(); } - this.refresher = setTimeout(() => { - console.log('refreshing token!'); - this.http.post(`${API_SETTINGS.apiURL}/auth/renewJwt`, {}, { headers: this.authHeader(), responseType: 'text' }).subscribe((response) => { - this.authenticate(response); - }); - }, exp.getTime() - new Date().getTime() - 60000); + var property=jwtHelper.decodeToken(this.cookie.get('token')); + var username=property['name']; + if(username!=""){ + this.refresher = setTimeout(() => { + console.log('refreshing token!'); + this.http.post(`${API_SETTINGS.apiURL}/auth/renewJwt`, {}, { headers: this.authHeader(), responseType: 'text' }).subscribe((response) => { + this.authenticate(response); + }); + }, exp.getTime() - new Date().getTime() - 60000); + } + else{ + this.refresher = setTimeout(() => { + console.log('refreshing token!'); + this.getGuestToken().subscribe((response) => { + this.authenticate(response); + }); + }, exp.getTime() - new Date().getTime() - 60000); + } + } + + addGuestToken(){ + this.getGuestToken().subscribe((token)=>{ + this.authenticate(token); + }); } authenticate(token: string) { @@ -74,6 +98,7 @@ export class AuthService { if (this.refresher) clearTimeout(this.refresher); this.shared.loggedIn = false; + this.addGuestToken(); } authHeader() { diff --git a/frontend/src/app/_services/datasets.service.ts b/frontend/src/app/_services/datasets.service.ts index 35ca24e5..0ff63828 100644 --- a/frontend/src/app/_services/datasets.service.ts +++ b/frontend/src/app/_services/datasets.service.ts @@ -16,7 +16,11 @@ export class DatasetsService { return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/publicdatasets`, { headers: this.authService.authHeader() }); } - addDataset(dataset: Dataset): any { + getMyDatasets(): Observable<Dataset[]> { + return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() }); + } + + addDataset(dataset: Dataset): Observable<any> { return this.http.post(`${API_SETTINGS.apiURL}/dataset/add`, dataset, { headers: this.authService.authHeader() }); } diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts index 74253fac..3fbad109 100644 --- a/frontend/src/app/_services/models.service.ts +++ b/frontend/src/app/_services/models.service.ts @@ -1,10 +1,10 @@ -import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'; +import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import Model from '../_data/Model'; import { AuthService } from './auth.service'; import { API_SETTINGS } from 'src/config'; -import Dataset from '../_data/Dataset'; import { Observable } from 'rxjs'; +import Dataset from '../_data/Dataset'; @Injectable({ @@ -35,25 +35,23 @@ export class ModelsService { addDataset(dataset: Dataset): Observable<any> { return this.http.post(`${API_SETTINGS.apiURL}/dataset/add`, dataset, { headers: this.authService.authHeader() }); } - trainModel(modelId: string): Observable<any> { - return this.http.post(`${API_SETTINGS.apiURL}/model/train`, modelId, { headers: this.authService.authHeader() }); + trainModel(model: Model): Observable<any> { + return this.http.post(`${API_SETTINGS.apiURL}/model/sendmodel`, model, { headers: this.authService.authHeader(), responseType: 'text' }); } getMyDatasets(): Observable<Dataset[]> { return this.http.get<Dataset[]>(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() }); } - + getMyModels(): Observable<Model[]> { return this.http.get<Model[]>(`${API_SETTINGS.apiURL}/model/mymodels`, { headers: this.authService.authHeader() }); } - editModel(model:Model) : Observable<Model> - { + editModel(model: Model): Observable<Model> { return this.http.put<Model>(`${API_SETTINGS.apiURL}/model/`, model, { headers: this.authService.authHeader() }); } - deleteModel(model:Model) - { - return this.http.delete(`${API_SETTINGS.apiURL}/model/`+model.name, { headers: this.authService.authHeader(), responseType : "text" }); + deleteModel(model: Model) { + return this.http.delete(`${API_SETTINGS.apiURL}/model/` + model.name, { headers: this.authService.authHeader(), responseType: "text" }); } } diff --git a/frontend/src/app/_services/web-socket.service.ts b/frontend/src/app/_services/web-socket.service.ts index 890ada6b..1a7efa87 100644 --- a/frontend/src/app/_services/web-socket.service.ts +++ b/frontend/src/app/_services/web-socket.service.ts @@ -13,15 +13,15 @@ export class WebSocketService { constructor() { this.ws = new WebsocketBuilder(API_SETTINGS.apiWSUrl) - .withBackoff(new ConstantBackoff(30000)) - .onOpen((i, e) => { console.log('WS: Connected to ' + API_SETTINGS.apiWSUrl) }) + .withBackoff(new ConstantBackoff(120000)) + .onOpen((i, e) => { /*console.log('WS: Connected to ' + API_SETTINGS.apiWSUrl)*/ }) .onMessage((i, e) => { console.log('WS MESSAGE: ', e.data); this.handlers.forEach(handler => { handler(e.data); }) }) - .onClose((i, e) => { console.log('WS: Connection closed!') }) + .onClose((i, e) => { /*console.log('WS: Connection closed!')*/ }) .build(); } diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index f5ae5786..8c6f8452 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Router, NavigationEnd, ActivatedRoute } from '@angular/router'; import { filter, map } from 'rxjs'; +import { AuthService } from './_services/auth.service'; @Component({ selector: 'app-root', @@ -10,7 +11,7 @@ import { filter, map } from 'rxjs'; }) export class AppComponent implements OnInit { - constructor(private router: Router, private titleService: Title) { } + constructor(private router: Router, private titleService: Title,private authService:AuthService) { } ngOnInit() { this.router.events @@ -33,5 +34,9 @@ export class AppComponent implements OnInit { this.titleService.setTitle(`${title} - Igrannonica`); } }); + if(!this.authService.isAuthenticated()) + { + this.authService.addGuestToken(); + } } } |