Commit 3f9b31bb authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

added frequency analysis data to improve the handling of matching exercises

parent 5abb07b5
{ {
"name": "mc_frontend", "name": "mc_frontend",
"version": "1.1.1", "version": "1.1.3",
"author": "Ionic Framework", "author": "Ionic Framework",
"homepage": "https://ionicframework.com/", "homepage": "https://ionicframework.com/",
"scripts": { "scripts": {
......
...@@ -12,7 +12,10 @@ import { ...@@ -12,7 +12,10 @@ import {
CaseTranslations, CaseTranslations,
CaseValue, CaseValue,
DependencyTranslation, DependencyTranslation,
DependencyValue, ExerciseType, ExerciseTypeTranslation, InstructionsTranslation, DependencyValue,
ExerciseType,
ExerciseTypeTranslation,
InstructionsTranslation,
PartOfSpeechTranslation, PartOfSpeechTranslation,
PartOfSpeechValue, PartOfSpeechValue,
Phenomenon Phenomenon
...@@ -22,9 +25,8 @@ import {LinkMC} from 'src/app/models/linkMC'; ...@@ -22,9 +25,8 @@ import {LinkMC} from 'src/app/models/linkMC';
import {QueryMC} from 'src/app/models/queryMC'; import {QueryMC} from 'src/app/models/queryMC';
import {Exercise} from 'src/app/models/exercise'; import {Exercise} from 'src/app/models/exercise';
import {Feedback} from 'src/app/models/feedback'; import {Feedback} from 'src/app/models/feedback';
import {PhenomenonMap} from 'src/app/models/phenomenonMap'; import {PhenomenonMap, PhenomenonMapContent} from 'src/app/models/phenomenonMap';
import {error} from 'selenium-webdriver'; import {FrequencyItem} from 'src/app/models/frequencyItem';
import {reject} from 'q';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
...@@ -51,7 +53,12 @@ export class CorpusService { ...@@ -51,7 +53,12 @@ export class CorpusService {
instructionsTranslation: '' instructionsTranslation: ''
}); });
public isTextRangeCorrect = false; public isTextRangeCorrect = false;
public phenomenonMap: PhenomenonMap = {}; public phenomenonMap: PhenomenonMap = new PhenomenonMap({
case: new PhenomenonMapContent({translationObject: CaseTranslations}),
dependency: new PhenomenonMapContent({translationObject: DependencyTranslation}),
lemma: new PhenomenonMapContent({translationObject: null}),
partOfSpeech: new PhenomenonMapContent({translationObject: PartOfSpeechTranslation})
});
constructor(public translate: TranslateService, constructor(public translate: TranslateService,
public http: HttpClient, public http: HttpClient,
...@@ -72,10 +79,10 @@ export class CorpusService { ...@@ -72,10 +79,10 @@ export class CorpusService {
}); });
} }
adjustQueryValue(query: QueryMC) { adjustQueryValue(query: QueryMC, queryIndex: number) {
const availableValues = Object.keys(this.phenomenonMap[query.phenomenon][2]); // when the phenomenon changes, choose the first value from the translated list as the default
// when the phenomenon changes, choose a (almost) random value as the default query.values = [this.getSortedQueryValues(query, queryIndex)[0]];
query.values = [availableValues[Object.keys(availableValues)[0]]]; this.updateBaseWord(query, queryIndex);
} }
adjustTranslations() { adjustTranslations() {
...@@ -86,16 +93,17 @@ export class CorpusService { ...@@ -86,16 +93,17 @@ export class CorpusService {
value => this.exercise.instructionsTranslation = value); value => this.exercise.instructionsTranslation = value);
} }
if (this.exercise.type === ExerciseType.matching) { if (this.exercise.type === ExerciseType.matching) {
this.exercise.queryItems = [new QueryMC({ this.exercise.queryItems = [new QueryMC({phenomenon: Phenomenon.partOfSpeech, values: []}),
phenomenon: Phenomenon.partOfSpeech, new QueryMC({phenomenon: Phenomenon.partOfSpeech, values: []})];
values: [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]], this.getFrequencyAnalysis().then(() => {
}), new QueryMC({ this.adjustQueryValue(this.exercise.queryItems[0], 0);
phenomenon: Phenomenon.partOfSpeech, this.adjustQueryValue(this.exercise.queryItems[1], 1);
values: [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]], return;
})]; });
} else if (this.exercise.queryItems.length > 1) { } else if (this.exercise.queryItems.length > 1) {
this.exercise.queryItems.splice(1, 1); this.exercise.queryItems.splice(1, 1);
} }
this.adjustQueryValue(this.exercise.queryItems[0], 0);
} }
checkAnnisResponse() { checkAnnisResponse() {
...@@ -106,6 +114,7 @@ export class CorpusService { ...@@ -106,6 +114,7 @@ export class CorpusService {
this.helperService.loadMostRecentSetup().then(() => { this.helperService.loadMostRecentSetup().then(() => {
this.annisResponse = HelperService.mostRecentSetup.annisResponse; this.annisResponse = HelperService.mostRecentSetup.annisResponse;
this.currentUrn = HelperService.mostRecentSetup.currentUrn; this.currentUrn = HelperService.mostRecentSetup.currentUrn;
this.currentCorpus = HelperService.mostRecentSetup.currentCorpus;
return outerResolve(); return outerResolve();
}, () => { }, () => {
return outerReject(); return outerReject();
...@@ -161,10 +170,58 @@ export class CorpusService { ...@@ -161,10 +170,58 @@ export class CorpusService {
return this.http.get(fullUrl, {params: {urn: urn}}); return this.http.get(fullUrl, {params: {urn: urn}});
} }
getSortedQueryValues(query: QueryMC) { getFrequencyAnalysis() {
const targetObject: object = this.phenomenonMap[query.phenomenon][0]; return new Promise((resolve, reject) => {
return Object.keys(this.phenomenonMap[query.phenomenon][2]).sort((a, b) => { if (this.annisResponse.frequency_analysis.length) {
return a === b ? 0 : (targetObject[a] < targetObject[b] ? -1 : 1); return resolve();
} else {
HelperService.currentError = null;
HelperService.isLoading = true;
const url = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiFrequencyPath'];
this.http.get(url, {params: {urn: this.currentUrn}}).subscribe((fis: FrequencyItem[]) => {
HelperService.isLoading = false;
this.annisResponse.frequency_analysis = fis;
HelperService.mostRecentSetup.annisResponse = this.annisResponse;
this.helperService.saveMostRecentSetup().then();
return resolve();
}, async (error: HttpErrorResponse) => {
HelperService.isLoading = false;
HelperService.currentError = error;
const toast = await this.toastCtrl.create({
message: HelperService.generalErrorAlertMessage,
duration: 3000,
position: 'top'
});
toast.present().then();
return reject();
});
}
});
}
getSortedQueryValues(query: QueryMC, queryIndex: number): string[] {
const pmc: PhenomenonMapContent = this.phenomenonMap[query.phenomenon];
if (this.exercise.type === ExerciseType.matching) {
if (queryIndex) {
const relevantFIs: FrequencyItem[] = this.annisResponse.frequency_analysis.filter(
x => x.values[0] === this.exercise.queryItems[0].values[0] &&
x.phenomena[1] === query.phenomenon.toString());
return Array.from(new Set<string>(relevantFIs.map(x => x.values[1]))).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
});
} else {
const relevantFIs: FrequencyItem[] = this.annisResponse.frequency_analysis.filter(
x => x.phenomena[0] === query.phenomenon.toString());
return Array.from(new Set<string>(relevantFIs.map(x => x.values[0]))).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
});
}
}
if (!pmc.specificValues) {
return [];
}
return Object.keys(pmc.specificValues).sort((a, b) => {
return a === b ? 0 : (pmc.translationValues[a] < pmc.translationValues[b] ? -1 : 1);
}); });
} }
...@@ -211,16 +268,14 @@ export class CorpusService { ...@@ -211,16 +268,14 @@ export class CorpusService {
initPhenomenonMap() { initPhenomenonMap() {
// map the different phenomena to their respective Enum for processing and display/translation // map the different phenomena to their respective Enum for processing and display/translation
this.phenomenonMap[Phenomenon.partOfSpeech] = [{}, PartOfSpeechTranslation, {}];
this.phenomenonMap[Phenomenon.dependency] = [{}, DependencyTranslation, {}];
this.phenomenonMap[Phenomenon.case] = [{}, CaseTranslations, {}];
this.phenomenonMap[Phenomenon.lemma] = [{}, null, {}];
Object.keys(Phenomenon).forEach((key) => { Object.keys(Phenomenon).forEach((key) => {
if (key !== Phenomenon[Phenomenon.lemma]) { if (key !== Phenomenon[Phenomenon.lemma]) {
const translationObject: object = this.phenomenonMap[key][1]; const pmc: PhenomenonMapContent = this.phenomenonMap[key];
pmc.translationValues = {};
const translationObject: object = pmc.translationObject;
Object.keys(translationObject).forEach((k: string) => { Object.keys(translationObject).forEach((k: string) => {
if (k !== k.toUpperCase()) { if (k !== k.toUpperCase()) {
this.translate.get(translationObject[k]).subscribe(v => this.phenomenonMap[key][0][k] = v); this.translate.get(translationObject[k]).subscribe(v => pmc.translationValues[k] = v);
} }
}); });
} }
...@@ -240,44 +295,26 @@ export class CorpusService { ...@@ -240,44 +295,26 @@ export class CorpusService {
} }
processAnnisResponse(ar: AnnisResponse, saveToCache: boolean = true) { processAnnisResponse(ar: AnnisResponse, saveToCache: boolean = true) {
Object.keys(this.phenomenonMap).forEach(key => this.phenomenonMap[key][2] = {}); Object.keys(this.phenomenonMap).forEach((key: string) => {
this.phenomenonMap[Phenomenon.lemma][0] = {}; const pmc: PhenomenonMapContent = this.phenomenonMap[key];
ar.nodes.forEach((node: NodeMC) => { pmc.specificValues = {};
let existingValue = this.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma];
this.phenomenonMap[Phenomenon.lemma][2][node.udep_lemma] = (existingValue ? existingValue : 0) + 1;
this.phenomenonMap[Phenomenon.lemma][0][node.udep_lemma] = node.udep_lemma;
if (node.udep_feats) {
const featsParts: string[] = node.udep_feats.split('|');
const casePart: string = featsParts.find(x => x.toLowerCase().includes(Phenomenon[Phenomenon.case]));
if (casePart) {
const caseAbbreviation: string = casePart.split('=')[1];
const caseValue: CaseValue = HelperService.caseMap[caseAbbreviation];
existingValue = this.phenomenonMap[Phenomenon.case][2][caseValue];
this.phenomenonMap[Phenomenon.case][2][caseValue] = (existingValue ? existingValue : 0) + 1;
}
}
const pos: PartOfSpeechValue = HelperService.partOfSpeechMap[node.udep_upostag];
existingValue = this.phenomenonMap[Phenomenon.partOfSpeech][2][pos];
this.phenomenonMap[Phenomenon.partOfSpeech][2][pos] = (existingValue ? existingValue : 0) + 1;
}); });
// init the display with a (almost) random value this.phenomenonMap.lemma.translationValues = {};
this.exercise.queryItems[0].values = [Object.keys(this.phenomenonMap[Phenomenon.partOfSpeech][2])[0]]; this.processNodes(ar);
const pointingLinks: LinkMC[] = ar.links.filter(x => x.annis_component_type === 'Pointing'); const pointingLinks: LinkMC[] = ar.links.filter(x => x.annis_component_type === 'Pointing');
pointingLinks.forEach((link: LinkMC) => { pointingLinks.forEach((link: LinkMC) => {
const dep: DependencyValue = HelperService.dependencyMap[link.udep_deprel]; const dep: DependencyValue = HelperService.dependencyMap[link.udep_deprel];
if (dep) { if (dep) {
const existingValue = this.phenomenonMap[Phenomenon.dependency][2][dep]; const existingValue = this.phenomenonMap.dependency.specificValues[dep];
this.phenomenonMap[Phenomenon.dependency][2][dep] = (existingValue ? existingValue : 0) + 1; this.phenomenonMap.dependency.specificValues[dep] = (existingValue ? existingValue : 0) + 1;
} }
}); });
// need to add root dependencies manually because they are tricky to handle // need to add root dependencies manually because they are tricky to handle
const nodeIds: string[] = ar.nodes.map(x => x.id); const nodeIds: string[] = ar.nodes.map(x => x.id);
const nodesWithDependencySet: Set<string> = new Set<string>(pointingLinks.map(x => x.target)); const nodesWithDependencySet: Set<string> = new Set<string>(pointingLinks.map(x => x.target));
const rootNodeIds: string[] = nodeIds.filter(x => !nodesWithDependencySet.has(x)); const rootNodeIds: string[] = nodeIds.filter(x => !nodesWithDependencySet.has(x));
this.phenomenonMap[Phenomenon.dependency][2][DependencyValue.root] = rootNodeIds.length; this.phenomenonMap.dependency.specificValues[DependencyValue.root] = rootNodeIds.length;
this.adjustQueryValue(this.exercise.queryItems[0]); this.adjustQueryValue(this.exercise.queryItems[0], 0);
// remove whitespace before punctuation // remove whitespace before punctuation
this.currentText = ar.nodes.map(x => x.annis_tok).join(' ').replace(/[ ]([.,\/#!$%\^&\*;:{}=\-_`~()])/g, (x: string) => { this.currentText = ar.nodes.map(x => x.annis_tok).join(' ').replace(/[ ]([.,\/#!$%\^&\*;:{}=\-_`~()])/g, (x: string) => {
return x.trim(); return x.trim();
...@@ -329,6 +366,27 @@ export class CorpusService { ...@@ -329,6 +366,27 @@ export class CorpusService {
}); });
} }
processNodes(ar: AnnisResponse) {
ar.nodes.forEach((node: NodeMC) => {
let existingValue = this.phenomenonMap.lemma.specificValues[node.udep_lemma];
this.phenomenonMap.lemma.specificValues[node.udep_lemma] = (existingValue ? existingValue : 0) + 1;
this.phenomenonMap.lemma.translationValues[node.udep_lemma] = node.udep_lemma;
if (node.udep_feats) {
const featsParts: string[] = node.udep_feats.split('|');
const casePart: string = featsParts.find(x => x.toLowerCase().includes(Phenomenon[Phenomenon.case]));
if (casePart) {
const caseAbbreviation: string = casePart.split('=')[1];
const caseValue: CaseValue = HelperService.caseMap[caseAbbreviation];
existingValue = this.phenomenonMap.case.specificValues[caseValue];
this.phenomenonMap.case.specificValues[caseValue] = (existingValue ? existingValue : 0) + 1;
}
}
const pos: PartOfSpeechValue = HelperService.partOfSpeechMap[node.udep_upostag];
existingValue = this.phenomenonMap.partOfSpeech.specificValues[pos];
this.phenomenonMap.partOfSpeech.specificValues[pos] = (existingValue ? existingValue : 0) + 1;
});
}
restoreLastCorpus() { restoreLastCorpus() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.annisResponse = HelperService.mostRecentSetup.annisResponse; this.annisResponse = HelperService.mostRecentSetup.annisResponse;
...@@ -350,4 +408,19 @@ export class CorpusService { ...@@ -350,4 +408,19 @@ export class CorpusService {
}); });
}); });
} }
updateBaseWord(query: QueryMC, queryIndex: number) {
if (!this.annisResponse || !this.annisResponse.frequency_analysis.length) {
return;
}
if (!queryIndex && this.exercise.type === ExerciseType.matching) {
if (!this.getSortedQueryValues(this.exercise.queryItems[1], 1).length) {
const fi: FrequencyItem = this.annisResponse.frequency_analysis.find(
x => x.values[0] === this.exercise.queryItems[0].values[0]);
this.exercise.queryItems[1].phenomenon = Phenomenon[fi.phenomena[1]];
}
this.adjustQueryValue(this.exercise.queryItems[1], 1);
}
}
} }
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
<label> <label>
<span class="label">{{ 'QUERY_PHENOMENON' | translate }}</span> <span class="label">{{ 'QUERY_PHENOMENON' | translate }}</span>
<select [(ngModel)]="query.phenomenon" name="queryPhenomenon" <select [(ngModel)]="query.phenomenon" name="queryPhenomenon"
(change)="corpusService.adjustQueryValue(query)"> (change)="corpusService.adjustQueryValue(query, i)">
<option *ngFor="let phenomenon of ObjectKeys(Phenomenon)" [value]=phenomenon> <option *ngFor="let phenomenon of ObjectKeys(Phenomenon)" [value]=phenomenon>
{{ PhenomenonTranslation[phenomenon] | translate }} {{ PhenomenonTranslation[phenomenon] | translate }}
</option> </option>
...@@ -63,9 +63,8 @@ ...@@ -63,9 +63,8 @@
<label> <label>
<span class="label">{{ 'QUERY_VALUE' | translate }}</span> <span class="label">{{ 'QUERY_VALUE' | translate }}</span>
<select [(ngModel)]="query.values" name="queryValue" multiple> <select [(ngModel)]="query.values" name="queryValue" multiple>
<option *ngFor="let key of corpusService.getSortedQueryValues(query)" [value]=key> <option *ngFor="let key of corpusService.getSortedQueryValues(query, i)"
{{ corpusService.phenomenonMap[query.phenomenon][0][key] + " (" + [value]=key>{{ getDisplayValue(query, key, i) }}
corpusService.phenomenonMap[query.phenomenon][2][key] + ")" }}
</option> </option>
</select> </select>
</label> </label>
...@@ -75,10 +74,10 @@ ...@@ -75,10 +74,10 @@
<span class="label"> <span class="label">
{{ 'QUERY_VALUE' | translate }} {{ 'QUERY_VALUE' | translate }}
</span> </span>
<select [(ngModel)]="query.values[0]" name="queryValue"> <select [(ngModel)]="query.values[0]" name="queryValue"
<option *ngFor="let key of corpusService.getSortedQueryValues(query)" [value]=key> (change)="corpusService.updateBaseWord(query, i)">
{{ corpusService.phenomenonMap[query.phenomenon][0][key] + " (" + <option *ngFor="let key of corpusService.getSortedQueryValues(query, i)"
corpusService.phenomenonMap[query.phenomenon][2][key] + ")" }} [value]=key>{{ getDisplayValue(query, key, i) }}
</option> </option>
</select> </select>
</label> </label>
......
...@@ -8,13 +8,15 @@ import { ...@@ -8,13 +8,15 @@ import {
} from '../models/enum'; } from '../models/enum';
import {AnnisResponse} from 'src/app/models/annisResponse'; import {AnnisResponse} from 'src/app/models/annisResponse';
import {NavController, ToastController} from '@ionic/angular'; import {NavController, ToastController} from '@ionic/angular';
import {QueryMC} from 'src/app/models/queryMC';
import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {ExerciseService} from 'src/app/exercise.service'; import {ExerciseService} from 'src/app/exercise.service';
import {HelperService} from 'src/app/helper.service'; import {HelperService} from 'src/app/helper.service';
import {CorpusService} from 'src/app/corpus.service'; import {CorpusService} from 'src/app/corpus.service';
import {QueryMC} from 'src/app/models/queryMC';
import {PhenomenonMapContent} from 'src/app/models/phenomenonMap';
import {FrequencyItem} from 'src/app/models/frequencyItem';
@Component({ @Component({
selector: 'app-exercise-parameters', selector: 'app-exercise-parameters',
...@@ -54,7 +56,8 @@ export class ExerciseParametersPage { ...@@ -54,7 +56,8 @@ export class ExerciseParametersPage {
position: 'top' position: 'top'
}); });
toast.present().then(); toast.present().then();
} else if (phenomenon === Phenomenon.lemma && !this.corpusService.exercise.queryItems[0].values) { } else if ((phenomenon === Phenomenon.lemma && !this.corpusService.exercise.queryItems[0].values) ||
this.corpusService.exercise.type === ExerciseType.matching && !this.corpusService.exercise.queryItems[1].values[0]) {
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({
message: this.emptyQueryValueString, message: this.emptyQueryValueString,
duration: 3000, duration: 3000,
...@@ -67,23 +70,41 @@ export class ExerciseParametersPage { ...@@ -67,23 +70,41 @@ export class ExerciseParametersPage {
} }
} }
public getDisplayValue(query: QueryMC, key: string, queryIndex: number = 0): string {
const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[query.phenomenon];
const translatedKey: string = pmc.translationValues[key];
let count: number;
if (this.corpusService.exercise.type === ExerciseType.matching) {
if (queryIndex) {
const relevantFI: FrequencyItem = this.corpusService.annisResponse.frequency_analysis.find(
x => x.values[0] === this.corpusService.exercise.queryItems[0].values[0] && x.values[1] === key);
count = relevantFI.count;
} else {
const relevantFIs: FrequencyItem[] = this.corpusService.annisResponse.frequency_analysis.filter(
x => x.phenomena[0] === query.phenomenon.toString() && x.values[0] === key);
count = relevantFIs.map(x => x.count).reduce((a, b) => a + b);
}
} else {
count = pmc.specificValues[key];
}
return translatedKey + ' (' + count + ')';
}
private getExerciseData() { private getExerciseData() {
const searchValues: string[] = this.corpusService.exercise.queryItems.map( const searchValues: string[] = this.corpusService.exercise.queryItems.map(
query => query.phenomenon + '=' + query.values.join('|')); query => query.phenomenon + '=' + query.values.join('|'));
const formData = new FormData(); const formData = new FormData();
formData.append('urn', this.corpusService.currentUrn); formData.append('urn', this.corpusService.currentUrn);
formData.append('search_values', JSON.stringify(searchValues)); formData.append('search_values', JSON.stringify(searchValues));
HelperService.currentError = null;
HelperService.isLoading = true;
let instructions: string = this.corpusService.exercise.instructionsTranslation; let instructions: string = this.corpusService.exercise.instructionsTranslation;
if (this.corpusService.exercise.type === ExerciseType.kwic) { if (this.corpusService.exercise.type === ExerciseType.kwic) {
this.getKwicExercise(formData); this.getKwicExercise(formData);
return; return;
} else if (this.corpusService.exercise.type === ExerciseType.markWords) { } else if (this.corpusService.exercise.type === ExerciseType.markWords) {
const phenomenon: Phenomenon = this.corpusService.exercise.queryItems[0].phenomenon; const phenomenon: Phenomenon = this.corpusService.exercise.queryItems[0].phenomenon;
const map: object[] = this.corpusService.phenomenonMap[phenomenon]; const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[phenomenon];
const values: string[] = this.corpusService.exercise.queryItems[0].values as string[]; const values: string[] = this.corpusService.exercise.queryItems[0].values as string[];
instructions += ` [${values.map(x => map[0][x]).join(', ')}]`; instructions += ` [${values.map(x => pmc.translationValues[x]).join(', ')}]`;
} }
// TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title // TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title
const workTitle: string = this.corpusService.currentCorpus.title + ', ' + const workTitle: string = this.corpusService.currentCorpus.title + ', ' +
...@@ -103,8 +124,12 @@ export class ExerciseParametersPage { ...@@ -103,8 +124,12 @@ export class ExerciseParametersPage {
getH5Pexercise(formData: FormData) { getH5Pexercise(formData: FormData) {
const url = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiExercisePath']; const url = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiExercisePath'];
HelperService.currentError = null;
HelperService.isLoading = true;
this.http.post(url, formData).subscribe((ar: AnnisResponse) => { this.http.post(url, formData).subscribe((ar: AnnisResponse) => {
HelperService.isLoading = false; HelperService.isLoading = false;
// save the old frequency analysis in case we want to change the exercise parameters at a later time
ar.frequency_analysis = this.corpusService.annisResponse.frequency_analysis;
HelperService.mostRecentSetup.annisResponse = ar; HelperService.mostRecentSetup.annisResponse = ar;
this.helperService.saveMostRecentSetup().then(); this.helperService.saveMostRecentSetup().then();
this.corpusService.annisResponse.exercise_id = ar.exercise_id; this.corpusService.annisResponse.exercise_id = ar.exercise_id;
...@@ -125,6 +150,8 @@ export class ExerciseParametersPage { ...@@ -125,6 +150,8 @@ export class ExerciseParametersPage {
getKwicExercise(formData: FormData) { getKwicExercise(formData: FormData) {
const kwicUrl: string = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiKwicPath']; const kwicUrl: string = HelperService.config['backendBaseUrl'] + HelperService.config['backendApiKwicPath'];
HelperService.currentError = null;
HelperService.isLoading = true;
this.http.post(kwicUrl, formData).subscribe((svgString: string) => { this.http.post(kwicUrl, formData).subscribe((svgString: string) => {
HelperService.isLoading = false; HelperService.isLoading = false;
this.exerciseService.kwicGraphs = svgString; this.exerciseService.kwicGraphs = svgString;
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
import {Solution} from 'src/app/models/solution'; import {Solution} from 'src/app/models/solution';
import {LinkMC} from 'src/app/models/linkMC'; import {LinkMC} from 'src/app/models/linkMC';
import {NodeMC} from 'src/app/models/nodeMC'; import {NodeMC} from 'src/app/models/nodeMC';
import {FrequencyItem} from 'src/app/models/frequencyItem';
export class AnnisResponse { export class AnnisResponse {
public directed: boolean; public directed: boolean;
public exercise_id: string; public exercise_id: string;
public frequency_analysis: FrequencyItem[];
public links: LinkMC[]; public links: LinkMC[];
public multigraph: boolean; public multigraph: boolean;
public nodes: NodeMC[]; public nodes: NodeMC[];
......
export class FrequencyItem {
public values: string[];
public phenomena: string[];
public count: number;
constructor(init?: Partial<FrequencyItem>) {
Object.assign(this, init);
}
}
/* tslint:disable:variable-name */
export class NodeMC { export class NodeMC {
public annis_node_name: string; public annis_node_name: string;