Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Result & Query Logging #145

Closed
wants to merge 10 commits into from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
src/config.json
deploy.log

src/app/**/*.js
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ For setup information, consult our [Wiki](https://github.com/vitrivr/vitrivr-ng/

## Config

There is a `config.json` which enables configuration of the UI to a certain extend.
While we provide a sensible [default config](src/config.json), the
some default values are better explored in the [code](src/app/shared/model/config/config.model.ts).
We follow a zero-config approach, where everything has reasonable defaults.
There is a `src/config.template.json` file which you can copy to `src/config.json` and modify if you have custom needs.
The default values are in the [code](src/app/shared/model/config/config.model.ts).
Information about the configuration can be found in [the wiki](https://github.com/vitrivr/vitrivr-ng/wiki/Configuration).

## Development server
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@
"ts-node": "10.7.0",
"tslint": "^6.1.3"
}
}
}
4 changes: 0 additions & 4 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,4 @@ export class AppComponent implements OnInit, AfterViewInit {
this._active_view = view;
}

isCompetitionActive() {
return this._configService.configAsObservable;
return this._config.dresEndpointRest && (this._config.get('competition.vbs') || this._config.get('competition.lsc'))
}
}
4 changes: 2 additions & 2 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ export class AppConfig {
AppConfig.settingsSubject.next(AppConfig.settings);
resolve();
}).catch((response: any) => {
this._snackBar.open('Could not parse config.json. Using default config, your UI may not work', 'Dismiss', {
this._snackBar.open('No config file present, using default config.', 'Dismiss', {
duration: 1_000_000,
verticalPosition: 'top'
})
AppConfig.settings = new Proxy<Config>(new Config(), this.handler);
AppConfig.settingsSubject.next(AppConfig.settings);
console.log(`Could not load config file '${jsonFile}'. Fallback to default.`);
console.log(`No config present at '${jsonFile}'. Using default.`);
resolve();
});
});
Expand Down
3 changes: 2 additions & 1 deletion src/app/core/basics/basic.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import {NotificationService} from './notification.service';
import {NoConnectDialogComponent} from './no-connect-dialog';
import {MatDialogModule} from '@angular/material/dialog';
import {MatButtonModule} from '@angular/material/button';
import {DresService} from './dres.service';

@NgModule({
imports: [HttpClientModule, MatDialogModule, MatButtonModule],
declarations: [NoConnectDialogComponent],
providers: [ResolverService, EventBusService, PingService, DatabaseService, KeyboardService, NotificationService]
providers: [ResolverService, EventBusService, PingService, DatabaseService, KeyboardService, NotificationService, DresService]
})

export class BasicModule {
Expand Down
9 changes: 5 additions & 4 deletions src/app/core/basics/database.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ export class DatabaseService {
*/
constructor() {
DatabaseService.DB.version(1).stores({
config: 'id,config',
history: '++id,timestamp',
log_results: '++id,log',
log_interaction: '++id,log',
log_submission: '++id,log'
log_results_dres: '++id,log',
log_interaction_dres: '++id,log',
log_submission_dres: '++id,log',
log_results: '++id,entry',
log_queries: '++id,entry',
});
}

Expand Down
92 changes: 92 additions & 0 deletions src/app/core/basics/dres.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {Injectable} from '@angular/core';
import {AppConfig} from '../../app.config';
import {ClientRunInfo, ClientRunInfoService, ClientTaskInfo, UserDetails, UserService} from '../../../../openapi/dres';
import {BehaviorSubject, Observable} from 'rxjs';

@Injectable()
export class DresService {

private _status: BehaviorSubject<UserDetails> = new BehaviorSubject(null)
private _activeRun: BehaviorSubject<ClientRunInfo> = new BehaviorSubject(null);
private _activeTask: BehaviorSubject<ClientTaskInfo> = new BehaviorSubject(null);

constructor(private _configService: AppConfig, private _runInfo: ClientRunInfoService, private _dresUser: UserService,) {
this._configService.configAsObservable.subscribe(config => {
if (config?.dresEndpointRest == null) {
return
}
this._dresUser.getApiV1User().subscribe(
{
next: (user) => {
this._status.next(user)
},
error: (error) => {
this._status.error(error)
}
})
}
)

// init dres info
this.updateDresInfo()

// update every 5 seconds
setInterval(
() => {
this.updateDresInfo()
},
5 * 1000
)

}

private updateDresInfo() {
if (this.getStatus() == null) {
return
}
this._runInfo.getApiV1ClientRunInfoList(this.getStatus().sessionId).subscribe(list => {
const l = list.runs.filter(info => info.status == 'ACTIVE');
const activeRun = l.length == 0 ? null : l[0]
this._activeRun.next(activeRun)
if (this._activeRun) {
this._runInfo.getApiV1ClientRunInfoCurrenttaskWithRunid(this._activeRun.getValue().id, this.getStatus().sessionId).subscribe(task => {
this._activeTask.next(task)
})
}
})
}

public statusObservable(): Observable<UserDetails> {
return this._status.asObservable()
}

public activeTaskObservable(): Observable<ClientTaskInfo> {
return this._activeTask.asObservable()
}

public activeRunObservable(): Observable<ClientRunInfo> {
return this._activeRun.asObservable()
}

public activeTask(): ClientTaskInfo {
return this._activeTask.getValue()
}

public activeRun(): ClientRunInfo {
return this._activeRun.getValue()
}

/**
* Returns null if an error was thrown during connection
*/
public getStatus(): UserDetails {
try {
if (this._status.getValue()) {
return this._status.getValue()
}
return null
} catch (e) {
return null
}
}
}
10 changes: 4 additions & 6 deletions src/app/core/basics/event-bus.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class EventBusService {
private _currentView: Subject<string> = new BehaviorSubject<string>(null);

/** The subject used to track the currently active view. */
private _lastQuery: Subject<InteractionEvent> = new BehaviorSubject<InteractionEvent>(null);
private _lastQuery = new BehaviorSubject<InteractionEvent>(null);

/**
* Publishes a nev InteractionEvent to the bus.
Expand All @@ -44,12 +44,10 @@ export class EventBusService {
}

/**
* Returns an observable that allows a consumer to be informed about the last query issued.
*
* @return {Observable<InteractionEvent>}
* Returns the latest query
*/
public lastQuery(): Observable<InteractionEvent> {
return this._lastQuery.asObservable()
public lastQueryInteractionEvent(): InteractionEvent {
return this._lastQuery.getValue()
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/app/core/basics/notification.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject, combineLatest, of} from 'rxjs';
import {VbsSubmissionService} from '../vbs/vbs-submission.service';
import {VbsSubmissionService} from '../competition/vbs-submission.service';
import {NotificationUtil} from '../../shared/util/notification.util';
import {catchError, tap} from 'rxjs/operators';
import {AppConfig} from '../../app.config';
import {DresService} from './dres.service';

@Injectable()
export class NotificationService {

private _dresStatusBadge = new BehaviorSubject('')

constructor(private _submissionService: VbsSubmissionService, private _configService: AppConfig) {
combineLatest([this._submissionService.statusObservable, this._configService.configAsObservable]).pipe(
constructor(private _submissionService: VbsSubmissionService, private _configService: AppConfig, private _dresService: DresService) {
combineLatest([this._dresService.statusObservable(), this._configService.configAsObservable]).pipe(
tap(([status, config]) => {
if (config._config.competition.host) {
/* Do not update observable for undefined since that is the initial value*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ import {AppConfig} from '../../app.config';
declarations: [],
providers: [VbsSubmissionService, CollabordinatorService]
})
export class VbsModule { }
export class CompetitionModule { }
50 changes: 50 additions & 0 deletions src/app/core/competition/logging/filter-information.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {MediaObjectDescriptor} from "../../../../../openapi/cineast";
import {ColorLabel} from "../../../shared/model/misc/colorlabel.model";
import {Tag} from "../../selection/tag.model";

/**
* A simple data class for logging
*/
export class FilterInformation {

/**
* When set to true, objects who have metadata matching for any of the categories are displayed.
*/
_useOrForMetadataCategoriesFilter = false;

_id: string;

/**
* A filter by MediaType. Affects both MediaObjectScoreContainers and MediaSegmentScoreContainers. If non-empty, only objects
* that match one of the MediaTypes contained in this array will pass the filter.
*/
_mediatypes: Map<MediaObjectDescriptor.MediatypeEnum, boolean> = new Map();

/**
* A filter by dominant color. Affects only MediaSegmentScoreContainers. If non-empty, only segments
* that match at least one of the dominant colors contained in this array will pass the filter.
*/
_dominant: Map<ColorLabel, boolean> = new Map();

/**
* A filter by metadata. For each metadata category (e.g. day), a list of allowed values is kept.
* If empty, all results are displayed. If non-empty, only results are displayed where for every key in the filter, the metadata value of the object matches an allowed value in the list.
* Behavior across categories is determined by a different boolean.
* If the object does not have one of the metadata keys, it is filtered.
*/
_filterMetadata: Map<string, Set<string>> = new Map();

/**
* A filter for tags. This is the list of allowed tag names. If the set is empty, no filter is applied.
*/
_filterTags: Set<Tag> = new Set();

/**
* A filter by metadata for numeric values.
* For each category, a min and max number is kept (or null)
*/
_filterRangeMetadata: Map<string, [number | null, number | null]> = new Map();

/** Threshold for score filtering. */
_threshold = 0.0;
}
7 changes: 7 additions & 0 deletions src/app/core/competition/logging/query-log-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {ClientRunInfo, ClientTaskInfo} from '../../../../../openapi/dres';

export interface QueryLogItem {
query: any,
dresTask: ClientTaskInfo,
dresRun: ClientRunInfo,
}
8 changes: 8 additions & 0 deletions src/app/core/competition/logging/result-log-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {FilterInformation} from "./filter-information";
import {SegmentScoreLogContainer} from "./segment-score-log-container";

export interface ResultLogItem {
filter: FilterInformation
query: any,
results: SegmentScoreLogContainer[],
}
15 changes: 15 additions & 0 deletions src/app/core/competition/logging/segment-score-log-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class SegmentScoreLogContainer {
public readonly objectId: string;
public readonly segmentId: string;
public readonly startabs: number;
public readonly endabs: number;
public readonly _score: number;

constructor(objectId: string, segmentId: string, startabs: number, endabs: number, score: number) {
this.objectId = objectId;
this.segmentId = segmentId;
this.startabs = startabs;
this.endabs = endabs;
this._score = score;
}
}
Loading