annotate src/app/services/feature-extraction/feature-extraction.service.ts @ 350:524f5cd75737

Split AnalysisItem out into individual types for root audio items and features. This is messy as is, these need revising and should perhaps be actual concrete types with methods.
author Lucas Thompson <dev@lucas.im>
date Fri, 26 May 2017 12:59:41 +0100
parents bf038a51f7e3
children 3eab26a629e1
rev   line source
dev@74 1 import {Injectable, Inject} from '@angular/core';
dev@47 2 import {
dev@226 3 ListResponse
dev@236 4 } from 'piper';
dev@64 5 import {
dev@350 6 SimpleRequest
dev@236 7 } from 'piper/HigherLevelUtilities';
dev@236 8 import {Subject} from 'rxjs/Subject';
dev@236 9 import {Observable} from 'rxjs/Observable';
dev@324 10 import {Http} from '@angular/http';
dev@226 11 import {
dev@226 12 countingIdProvider,
dev@226 13 WebWorkerStreamingClient
dev@236 14 } from 'piper/client-stubs/WebWorkerStreamingClient';
dev@236 15 import {RequestId} from 'piper/protocols/WebWorkerProtocol';
dev@316 16 import {collect, StreamingConfiguration} from 'piper/StreamingService';
dev@349 17 import {
dev@349 18 KnownShapedFeature,
dev@349 19 toKnownShape
dev@349 20 } from '../../visualisations/FeatureUtilities';
dev@40 21
dev@74 22 type RepoUri = string;
dev@74 23 export interface AvailableLibraries {
dev@74 24 [libraryKey: string]: RepoUri;
dev@74 25 }
dev@74 26
dev@226 27 export interface Progress {
dev@226 28 id: RequestId;
dev@226 29 value: number; // between 0 and 100, for material-ui
dev@226 30 }
dev@226 31
dev@350 32 export interface ExtractionResult {
dev@350 33 id: RequestId;
dev@350 34 result: KnownShapedFeature;
dev@350 35 }
dev@350 36
dev@40 37 @Injectable()
dev@40 38 export class FeatureExtractionService {
dev@40 39
dev@40 40 private worker: Worker;
dev@350 41 private featuresExtracted: Subject<ExtractionResult>;
dev@350 42 featuresExtracted$: Observable<ExtractionResult>;
dev@74 43 private librariesUpdated: Subject<ListResponse>;
dev@74 44 librariesUpdated$: Observable<ListResponse>;
dev@226 45 private progressUpdated: Subject<Progress>;
dev@226 46 progressUpdated$: Observable<Progress>;
dev@226 47 private client: WebWorkerStreamingClient;
dev@44 48
dev@236 49 constructor(private http: Http,
dev@236 50 @Inject('PiperRepoUri') private repositoryUri: RepoUri) {
dev@40 51 this.worker = new Worker('bootstrap-feature-extraction-worker.js');
dev@350 52 this.featuresExtracted = new Subject<ExtractionResult>();
dev@51 53 this.featuresExtracted$ = this.featuresExtracted.asObservable();
dev@74 54 this.librariesUpdated = new Subject<ListResponse>();
dev@74 55 this.librariesUpdated$ = this.librariesUpdated.asObservable();
dev@226 56 this.progressUpdated = new Subject<Progress>();
dev@226 57 this.progressUpdated$ = this.progressUpdated.asObservable();
dev@74 58 this.worker.addEventListener('message', (ev: MessageEvent) => {
dev@74 59 const isValidResponse = ev.data.method === 'import'
dev@226 60 && ev.data.result && ev.data.result.available ;
dev@74 61 if (isValidResponse) {
dev@226 62 (ev as Event).stopImmediatePropagation();
dev@74 63 this.librariesUpdated.next(ev.data.result);
dev@74 64 }
dev@226 65 }, true);
dev@226 66
dev@226 67 this.client = new WebWorkerStreamingClient(
dev@226 68 this.worker,
dev@226 69 countingIdProvider(0)
dev@236 70 );
dev@40 71 }
dev@40 72
dev@47 73 list(): Promise<ListResponse> {
dev@326 74 return this.client.list({});
dev@40 75 }
dev@40 76
dev@350 77 extract(analysisItemId: string,
dev@350 78 request: SimpleRequest): Promise<ExtractionResult> {
dev@305 79 let config: StreamingConfiguration;
dev@305 80 return collect(this.client.process(request), val => {
dev@305 81 if (val.configuration) {
dev@305 82 config = val.configuration;
dev@305 83 }
dev@305 84 const progress = val.progress;
dev@305 85 if (progress.totalBlockCount > 0) {
dev@305 86 this.progressUpdated.next({
dev@305 87 id: analysisItemId,
dev@305 88 value: (progress.processedBlockCount / progress.totalBlockCount) * 100
dev@305 89 });
dev@305 90 }
dev@305 91 }).then(features => {
dev@349 92 const shaped = toKnownShape({
dev@305 93 features: features,
dev@305 94 outputDescriptor: config.outputDescriptor
dev@226 95 });
dev@350 96 const result = {
dev@350 97 id: analysisItemId,
dev@350 98 result: shaped
dev@350 99 };
dev@350 100 this.featuresExtracted.next(result);
dev@350 101 return result;
dev@305 102 });
dev@62 103 }
dev@62 104
dev@324 105 updateAvailableLibraries(): void {
dev@324 106 this.http.get(this.repositoryUri)
dev@324 107 .toPromise() // just turn into a promise for now to subscribe / execute
dev@324 108 .then(res => {
dev@74 109 this.worker.postMessage({
dev@74 110 method: 'addRemoteLibraries',
dev@324 111 params: res.json()
dev@349 112 });
dev@74 113 })
dev@324 114 .catch(console.error); // TODO Report error to user
dev@74 115 }
dev@74 116
dev@74 117 load(libraryKey: string): void {
dev@74 118 this.worker.postMessage({method: 'import', params: libraryKey});
dev@74 119 }
dev@40 120 }