Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
callidus
Machina Callida
Commits
b98bed42
Commit
b98bed42
authored
Jan 22, 2021
by
Konstantin Schulz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixed a bug where the frequency analysis data for matching exercises would be deleted
parent
abc6d52e
Pipeline
#15736
passed with stages
in 2 minutes and 45 seconds
Changes
25
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
175 additions
and
158 deletions
+175
-158
deploy.sh
deploy.sh
+1
-2
mc_backend/mcserver/config.py
mc_backend/mcserver/config.py
+2
-1
mc_backend/requirements.txt
mc_backend/requirements.txt
+1
-1
mc_backend/tests.py
mc_backend/tests.py
+7
-7
mc_frontend/package.json
mc_frontend/package.json
+1
-1
mc_frontend/src/app/author-detail/author-detail.page.html
mc_frontend/src/app/author-detail/author-detail.page.html
+2
-2
mc_frontend/src/app/author/author.page.ts
mc_frontend/src/app/author/author.page.ts
+1
-1
mc_frontend/src/app/corpus.service.spec.ts
mc_frontend/src/app/corpus.service.spec.ts
+46
-46
mc_frontend/src/app/corpus.service.ts
mc_frontend/src/app/corpus.service.ts
+34
-28
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.html
...src/app/exercise-parameters/exercise-parameters.page.html
+5
-5
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.spec.ts
.../app/exercise-parameters/exercise-parameters.page.spec.ts
+1
-1
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.ts
...d/src/app/exercise-parameters/exercise-parameters.page.ts
+10
-11
mc_frontend/src/app/exercise.service.spec.ts
mc_frontend/src/app/exercise.service.spec.ts
+4
-4
mc_frontend/src/app/exercise.service.ts
mc_frontend/src/app/exercise.service.ts
+5
-5
mc_frontend/src/app/helper.service.ts
mc_frontend/src/app/helper.service.ts
+10
-12
mc_frontend/src/app/models/applicationState.ts
mc_frontend/src/app/models/applicationState.ts
+2
-1
mc_frontend/src/app/models/mockMC.ts
mc_frontend/src/app/models/mockMC.ts
+5
-6
mc_frontend/src/app/models/queryMC.ts
mc_frontend/src/app/models/queryMC.ts
+2
-1
mc_frontend/src/app/preview/preview.page.html
mc_frontend/src/app/preview/preview.page.html
+2
-2
mc_frontend/src/app/preview/preview.page.spec.ts
mc_frontend/src/app/preview/preview.page.spec.ts
+8
-8
mc_frontend/src/app/preview/preview.page.ts
mc_frontend/src/app/preview/preview.page.ts
+12
-10
mc_frontend/src/app/ranking/ranking.page.spec.ts
mc_frontend/src/app/ranking/ranking.page.spec.ts
+1
-1
mc_frontend/src/app/text-range/text-range.page.ts
mc_frontend/src/app/text-range/text-range.page.ts
+1
-1
mc_frontend/src/version.ts
mc_frontend/src/version.ts
+1
-1
mc_frontend/update_version.py
mc_frontend/update_version.py
+11
-0
No files found.
deploy.sh
View file @
b98bed42
x
=
$(
git tag
--points-at
HEAD
)
echo
"export const version = '
${
x
}
';"
>
mc_frontend/src/version.ts
python ./mc_frontend/update_version.py
docker-compose build
docker-compose down
docker-compose up
-d
mc_backend/mcserver/config.py
View file @
b98bed42
...
...
@@ -30,6 +30,7 @@ class Config(object):
-
1
]
==
"mcserver"
else
MC_SERVER_DIRECTORY
IS_DOCKER
=
os
.
environ
.
get
(
"IS_THIS_A_DOCKER_CONTAINER"
,
False
)
MC_FRONTEND_DIRECTORY
=
os
.
path
.
join
(
Path
(
MC_SERVER_DIRECTORY
).
parent
.
parent
,
"mc_frontend"
)
MC_FRONTEND_SRC_DIRECTORY
=
os
.
path
.
join
(
MC_FRONTEND_DIRECTORY
,
"src"
)
ASSETS_DIRECTORY
=
os
.
path
.
join
(
MC_SERVER_APP_DIRECTORY
,
"assets"
)
FILES_DIRECTORY
=
os
.
path
.
join
(
MC_SERVER_APP_DIRECTORY
,
"files"
)
TMP_DIRECTORY
=
os
.
path
.
join
(
FILES_DIRECTORY
,
"tmp"
)
...
...
@@ -97,7 +98,7 @@ class Config(object):
FLASK_MIGRATE
=
"migrate"
GRAPHANNIS_DEPENDENCY_LINK
=
"dep"
GRAPHANNIS_LOG_PATH
=
os
.
path
.
join
(
os
.
getcwd
(),
"graphannis.log"
)
H5P_DIRECTORY
=
"/home/mc/h5p"
if
IS_DOCKER
else
os
.
path
.
join
(
MC_FRONTEND_DIRECTORY
,
"src"
,
"assets"
,
"h5p"
)
H5P_DIRECTORY
=
"/home/mc/h5p"
if
IS_DOCKER
else
os
.
path
.
join
(
MC_FRONTEND_
SRC_
DIRECTORY
,
"assets"
,
"h5p"
)
# Windows: use 127.0.0.1 as host IP fallback
HOST_IP_FALLBACK
=
"0.0.0.0"
HOST_IP_CSM
=
DOCKER_SERVICE_NAME_CSM
if
IS_DOCKER
else
HOST_IP_FALLBACK
...
...
mc_backend/requirements.txt
View file @
b98bed42
...
...
@@ -40,7 +40,7 @@ jmespath==0.9.5
jsonschema==3.2.0
kiwisolver==1.2.0
LinkHeader==0.4.3
lxml==4.
5.0
lxml==4.
6.2
Mako==1.1.2
MarkupSafe==1.1.1
matplotlib==3.2.1
...
...
mc_backend/tests.py
View file @
b98bed42
...
...
@@ -23,7 +23,6 @@ from typing import Dict, List, Tuple, Type, Any
from
conllu
import
TokenList
from
flask
import
Flask
from
gensim.models
import
Word2Vec
from
graphannis.graph
import
GraphUpdate
from
lxml
import
etree
from
networkx
import
MultiDiGraph
,
Graph
from
requests
import
HTTPError
...
...
@@ -38,15 +37,16 @@ from mcserver.app import create_app, db, start_updater, full_init
from
mcserver.app.api.exerciseAPI
import
map_exercise_data_to_database
from
mcserver.app.models
import
ResourceType
,
FileType
,
ExerciseType
,
ExerciseData
,
\
NodeMC
,
LinkMC
,
GraphData
,
Phenomenon
,
CustomCorpus
,
AnnisResponse
,
Solution
,
DownloadableFile
,
Language
,
\
VocabularyCorpus
,
TextComplexityMeasure
,
CitationLevel
,
FrequencyItem
,
TextComplexity
,
Dependency
,
PartOfSpeech
,
\
Choice
,
XapiStatement
,
ExerciseMC
,
CorpusMC
,
make_solution_element_from_salt_id
,
Sentence
,
ReferenceableText
from
mcserver.app.services
import
AnnotationService
,
CorpusService
,
FileService
,
CustomCorpusService
,
DatabaseService
,
\
XMLservice
,
TextService
,
FrequencyService
,
ExerciseService
VocabularyCorpus
,
TextComplexityMeasure
,
CitationLevel
,
FrequencyItem
,
TextComplexity
,
Dependency
,
\
PartOfSpeech
,
Choice
,
XapiStatement
,
ExerciseMC
,
CorpusMC
,
make_solution_element_from_salt_id
,
Sentence
,
\
ReferenceableText
from
mcserver.app.services
import
AnnotationService
,
CorpusService
,
FileService
,
CustomCorpusService
,
\
DatabaseService
,
XMLservice
,
TextService
,
FrequencyService
,
ExerciseService
from
mcserver.config
import
TestingConfig
,
Config
from
mcserver.models_auto
import
Corpus
,
Exercise
,
UpdateInfo
,
LearningResult
from
mocks
import
Mocks
,
MockResponse
,
MockW2V
,
MockQuery
,
TestHelper
from
openapi.openapi_server.models
import
VocabularyForm
,
VocabularyMC
,
TextComplexityForm
,
ExerciseForm
,
KwicForm
,
\
VectorNetworkForm
,
MatchingExercise
,
ExerciseTypePath
,
H5PForm
from
openapi.openapi_server.models
import
VocabularyForm
,
VocabularyMC
,
TextComplexityForm
,
ExerciseForm
,
\
KwicForm
,
VectorNetworkForm
,
MatchingExercise
,
ExerciseTypePath
,
H5PForm
class
McTestCase
(
unittest
.
TestCase
):
...
...
mc_frontend/package.json
View file @
b98bed42
...
...
@@ -5,7 +5,7 @@
"homepage"
:
"https://ionicframework.com/"
,
"scripts"
:
{
"ng"
:
"ng"
,
"start"
:
"ng serve --port 8100"
,
"start"
:
"
python update_version.py &&
ng serve --port 8100"
,
"build"
:
"ng build"
,
"test-ci"
:
"ng test --code-coverage --watch=false"
,
"test-cov"
:
"ng test --code-coverage --watch=true"
,
...
...
mc_frontend/src/app/author-detail/author-detail.page.html
View file @
b98bed42
...
...
@@ -8,7 +8,7 @@
</div>
</ion-buttons>
<ion-spinner
*ngIf=
"helperService.openRequests.length"
></ion-spinner>
<ion-title
*ngIf=
"helperService.applicationState | async as state"
>
{{ state.
curr
entSetup.currentAuthor?.name }}
</ion-title>
<ion-title
*ngIf=
"helperService.applicationState | async as state"
>
{{ state.
mostRec
entSetup.currentAuthor?.name }}
</ion-title>
<ion-buttons
slot=
"end"
>
<ion-menu-button
autoHide=
"false"
>
<ion-icon
name=
"menu"
></ion-icon>
...
...
@@ -20,7 +20,7 @@
<ion-content
class=
"ion-padding"
>
<ion-list
*ngIf=
"helperService.applicationState | async as state"
>
<ion-item
*ngFor=
"let corpus of state.
curr
entSetup.currentAuthor?.corpora"
>
<ion-item
*ngFor=
"let corpus of state.
mostRec
entSetup.currentAuthor?.corpora"
>
<button
(click)=
"showPossibleReferences(corpus)"
>
<span>
{{corpus.title}}
</span>
</button>
...
...
mc_frontend/src/app/author/author.page.ts
View file @
b98bed42
...
...
@@ -95,7 +95,7 @@ export class AuthorPage implements OnInit {
showCorpora
(
author
:
Author
):
void
{
this
.
corpusService
.
currentAuthor
=
author
;
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
as
:
ApplicationState
)
=>
{
as
.
curr
entSetup
.
currentAuthor
=
author
;
as
.
mostRec
entSetup
.
currentAuthor
=
author
;
this
.
helperService
.
saveApplicationState
(
as
).
then
();
this
.
helperService
.
goToPage
(
this
.
navCtrl
,
configMC
.
pageUrlAuthorDetail
).
then
();
});
...
...
mc_frontend/src/app/corpus.service.spec.ts
View file @
b98bed42
import
{
fakeAsync
,
flushMicrotasks
,
TestBed
}
from
'
@angular/core/testing
'
;
import
{
TestBed
}
from
'
@angular/core/testing
'
;
import
{
CorpusService
}
from
'
./corpus.service
'
;
import
{
IonicStorageModule
}
from
'
@ionic/storage
'
;
...
...
@@ -19,10 +19,9 @@ import {CorpusMC} from './models/corpusMC';
import
{
Author
}
from
'
./models/author
'
;
import
{
take
}
from
'
rxjs/operators
'
;
import
{
TextRange
}
from
'
./models/textRange
'
;
import
Spy
=
jasmine
.
Spy
;
import
{
AnnisResponse
,
NodeMC
}
from
'
../../openapi
'
;
import
{
Phenomenon
}
from
'
../../openapi
'
;
import
{
AnnisResponse
,
NodeMC
,
Phenomenon
}
from
'
../../openapi
'
;
import
{
ReplaySubject
,
Subscription
}
from
'
rxjs
'
;
import
Spy
=
jasmine
.
Spy
;
describe
(
'
CorpusService
'
,
()
=>
{
let
httpClient
:
HttpClient
;
...
...
@@ -51,7 +50,9 @@ describe('CorpusService', () => {
it
(
'
should adjust translations
'
,
(
done
)
=>
{
spyOn
(
corpusService
.
helperService
,
'
makeGetRequest
'
).
and
.
returnValue
(
Promise
.
resolve
(
MockMC
.
apiResponseFrequencyAnalysisGet
));
spyOn
(
corpusService
,
'
getSortedQueryValues
'
).
and
.
returnValue
([
PartOfSpeechValue
.
adjective
.
toString
()]);
spyOn
(
corpusService
,
'
getSortedQueryValues
'
).
and
.
callFake
((
query
:
QueryMC
,
queryIndex
:
number
)
=>
{
query
.
availableValues
=
[
PartOfSpeechValue
.
adjective
];
});
corpusService
.
helperService
.
applicationState
.
next
(
corpusService
.
helperService
.
deepCopy
(
MockMC
.
applicationState
)
as
ApplicationState
);
corpusService
.
exercise
.
type
=
ExerciseType
.
matching
;
...
...
@@ -79,22 +80,16 @@ describe('CorpusService', () => {
stateSpy
.
and
.
returnValue
(
state
.
pipe
(
take
(
1
)));
corpusService
.
annisResponse
=
undefined
;
corpusService
.
checkAnnisResponse
().
then
(()
=>
{
},
()
=>
{
},
async
()
=>
{
expect
(
corpusService
.
annisResponse
).
toBeFalsy
();
state
=
new
ReplaySubject
<
ApplicationState
>
();
state
.
next
(
corpusService
.
helperService
.
deepCopy
(
MockMC
.
applicationState
)
as
ApplicationState
);
stateSpy
.
and
.
returnValue
(
state
.
pipe
(
take
(
1
)));
corpusService
.
checkAnnisResponse
().
then
(()
=>
{
expect
(
corpusService
.
annisResponse
).
toBeTruthy
();
corpusService
.
checkAnnisResponse
().
then
(()
=>
{
expect
(
corpusService
.
annisResponse
).
toBeTruthy
();
done
();
},
()
=>
{
console
.
log
(
'
FOURTH CHECK FAILED
'
);
});
},
()
=>
{
console
.
log
(
'
THIRD CHECK FAILED
'
);
});
await
corpusService
.
checkAnnisResponse
();
expect
(
corpusService
.
annisResponse
).
toBeTruthy
();
await
corpusService
.
checkAnnisResponse
();
expect
(
corpusService
.
annisResponse
).
toBeTruthy
();
done
();
});
});
});
...
...
@@ -193,13 +188,13 @@ describe('CorpusService', () => {
it
(
'
should get sorted query values
'
,
()
=>
{
corpusService
.
exercise
.
type
=
ExerciseType
.
cloze
;
const
query
:
QueryMC
=
new
QueryMC
({
phenomenon
:
Phenomenon
.
Upostag
});
let
result
:
string
[]
=
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
result
.
length
).
toBe
(
0
);
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
query
.
availableValues
.
length
).
toBe
(
0
);
const
pmc
:
PhenomenonMapContent
=
corpusService
.
phenomenonMap
[
query
.
phenomenon
];
pmc
.
specificValues
=
{
a
:
0
,
b
:
1
,
c
:
2
};
pmc
.
translationValues
=
{
a
:
'
a
'
,
b
:
'
c
'
,
c
:
'
b
'
};
result
=
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
result
.
length
).
toBe
(
3
);
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
query
.
availableValues
.
length
).
toBe
(
3
);
corpusService
.
exercise
.
type
=
ExerciseType
.
matching
;
corpusService
.
annisResponse
=
{
frequency_analysis
:
[{
...
...
@@ -213,14 +208,14 @@ describe('CorpusService', () => {
phenomena
:
[
Phenomenon
.
Upostag
,
Phenomenon
.
Upostag
]
}]
};
result
=
corpusService
.
getSortedQueryValues
(
query
,
1
);
expect
(
result
.
length
).
toBe
(
3
);
corpusService
.
getSortedQueryValues
(
query
,
1
);
expect
(
query
.
availableValues
.
length
).
toBe
(
3
);
corpusService
.
annisResponse
.
frequency_analysis
.
forEach
(
fi
=>
fi
.
phenomena
=
[
Phenomenon
.
Upostag
]);
corpusService
.
annisResponse
.
frequency_analysis
[
0
].
values
[
0
]
=
'
a
'
;
corpusService
.
annisResponse
.
frequency_analysis
[
1
].
values
[
0
]
=
'
b
'
;
corpusService
.
annisResponse
.
frequency_analysis
[
2
].
values
[
0
]
=
'
c
'
;
result
=
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
result
.
length
).
toBe
(
3
);
corpusService
.
getSortedQueryValues
(
query
,
0
);
expect
(
query
.
availableValues
.
length
).
toBe
(
3
);
});
it
(
'
should get text
'
,
(
done
)
=>
{
...
...
@@ -267,33 +262,38 @@ describe('CorpusService', () => {
});
});
it
(
'
should initialize the current corpus
'
,
fakeAsync
((
)
=>
{
corpusService
.
helperService
.
applicationState
.
next
(
new
ApplicationState
());
it
(
'
should initialize the current corpus
'
,
((
done
)
=>
{
corpusService
.
helperService
.
applicationState
.
next
(
new
ApplicationState
(
{
mostRecentSetup
:
new
TextData
()}
));
let
corpus
:
CorpusMC
=
{
source_urn
:
''
};
const
subscriptions
:
Subscription
[]
=
[];
function
initCorpus
():
void
{
subscriptions
.
forEach
((
sub
:
Subscription
,
idx
:
number
,
subList
:
Subscription
[])
=>
{
sub
.
unsubscribe
();
delete
subList
[
idx
];
});
corpusService
.
initCurrentCorpus
().
then
(()
=>
{
subscriptions
.
push
(
corpusService
.
currentCorpus
.
subscribe
((
cc
:
CorpusMC
)
=>
{
corpus
=
cc
;
}));
function
initCorpus
():
Promise
<
void
>
{
return
new
Promise
<
void
>
(
resolve
=>
{
subscriptions
.
forEach
((
sub
:
Subscription
,
idx
:
number
,
subList
:
Subscription
[])
=>
{
sub
.
unsubscribe
();
delete
subList
[
idx
];
});
corpusService
.
initCurrentCorpus
().
then
(()
=>
{
subscriptions
.
push
(
corpusService
.
currentCorpus
.
subscribe
((
cc
:
CorpusMC
)
=>
{
corpus
=
cc
;
return
resolve
();
}));
});
});
flushMicrotasks
();
}
initCorpus
();
// first subscription will not resolve because the current corpus is null
initCorpus
().
then
();
expect
(
corpus
.
source_urn
).
toBeFalsy
();
corpusService
.
helperService
.
applicationState
.
next
(
corpusService
.
helperService
.
deepCopy
(
MockMC
.
applicationState
)
as
ApplicationState
);
initCorpus
();
expect
(
corpus
.
source_urn
).
toBeTruthy
();
corpus
=
undefined
;
initCorpus
();
expect
(
corpus
).
toBeTruthy
();
initCorpus
().
then
(
async
()
=>
{
expect
(
corpus
.
source_urn
).
toBeTruthy
();
corpus
=
undefined
;
await
initCorpus
();
expect
(
corpus
).
toBeTruthy
();
done
();
});
}));
it
(
'
should load corpora from local storage
'
,
(
done
)
=>
{
...
...
@@ -417,14 +417,14 @@ describe('CorpusService', () => {
it
(
'
should update the base word
'
,
()
=>
{
const
adjustSpy
:
Spy
=
spyOn
(
corpusService
,
'
adjustQueryValue
'
);
const
queryValuesSpy
:
Spy
=
spyOn
(
corpusService
,
'
getSortedQueryValues
'
)
.
and
.
returnValue
([])
;
const
queryValuesSpy
:
Spy
=
spyOn
(
corpusService
,
'
getSortedQueryValues
'
);
corpusService
.
annisResponse
=
{
frequency_analysis
:
corpusService
.
helperService
.
deepCopy
(
MockMC
.
apiResponseFrequencyAnalysisGet
)
};
corpusService
.
annisResponse
.
frequency_analysis
[
0
].
phenomena
.
push
(
Phenomenon
.
Feats
);
corpusService
.
exercise
.
type
=
ExerciseType
.
matching
;
corpusService
.
exercise
.
queryItems
.
push
(
new
QueryMC
());
corpusService
.
updateBaseWord
(
new
QueryMC
()
,
0
);
corpusService
.
exercise
.
queryItems
.
push
(
new
QueryMC
(
{
selectedValues
:
[]}
));
corpusService
.
updateBaseWord
(
corpusService
.
exercise
.
queryItems
.
slice
(
-
1
)[
0
]
,
0
);
expect
(
adjustSpy
).
toHaveBeenCalledTimes
(
1
);
expect
(
queryValuesSpy
).
toHaveBeenCalledTimes
(
1
);
expect
(
corpusService
.
exercise
.
queryItems
[
1
].
phenomenon
).
toBe
(
Phenomenon
.
Feats
);
...
...
mc_frontend/src/app/corpus.service.ts
View file @
b98bed42
...
...
@@ -25,7 +25,6 @@ import {PhenomenonMap, PhenomenonMapContent} from 'src/app/models/phenomenonMap'
import
{
ReplaySubject
}
from
'
rxjs
'
;
import
{
ApplicationState
}
from
'
./models/applicationState
'
;
import
{
take
}
from
'
rxjs/operators
'
;
import
{
TextData
}
from
'
./models/textData
'
;
import
{
Storage
}
from
'
@ionic/storage
'
;
import
{
UpdateInfo
}
from
'
./models/updateInfo
'
;
import
configMC
from
'
../configMC
'
;
...
...
@@ -58,8 +57,9 @@ export class CorpusService {
type
:
ExerciseType
.
cloze
,
typeTranslation
:
''
,
queryItems
:
[
new
QueryMC
({
availableValues
:
[],
phenomenon
:
Phenomenon
.
Upostag
,
v
alues
:
[
PartOfSpeechValue
.
adjective
],
selectedV
alues
:
[
PartOfSpeechValue
.
adjective
],
})],
feedback
:
new
Feedback
({
general
:
''
,
incorrect
:
''
,
partiallyCorrect
:
''
,
correct
:
''
}),
instructionsTranslation
:
''
...
...
@@ -75,6 +75,7 @@ export class CorpusService {
lemma
:
new
PhenomenonMapContent
({
translationObject
:
null
}),
upostag
:
new
PhenomenonMapContent
({
translationObject
:
PartOfSpeechTranslation
})
});
public
previewAnnisResponse
:
AnnisResponse
;
public
searchRegexMissingString
:
string
;
public
shareLinkCopiedString
:
string
;
public
textTooLongString
:
string
;
...
...
@@ -89,8 +90,9 @@ export class CorpusService {
}
adjustQueryValue
(
query
:
QueryMC
,
queryIndex
:
number
):
void
{
this
.
getSortedQueryValues
(
query
,
queryIndex
);
// when the phenomenon changes, choose the first value from the translated list as the default
query
.
values
=
[
this
.
getSortedQueryValues
(
query
,
queryIndex
)[
0
]]
;
query
.
selectedValues
=
query
.
availableValues
.
slice
(
0
,
1
)
;
this
.
updateBaseWord
(
query
,
queryIndex
);
}
...
...
@@ -103,8 +105,8 @@ export class CorpusService {
value
=>
this
.
exercise
.
instructionsTranslation
=
value
);
}
if
(
this
.
exercise
.
type
===
ExerciseType
.
matching
)
{
this
.
exercise
.
queryItems
=
[
new
QueryMC
({
phenomenon
:
Phenomenon
.
Upostag
,
v
alues
:
[]}),
new
QueryMC
({
phenomenon
:
Phenomenon
.
Upostag
,
v
alues
:
[]})];
this
.
exercise
.
queryItems
=
[
new
QueryMC
({
phenomenon
:
Phenomenon
.
Upostag
,
selectedV
alues
:
[]}),
new
QueryMC
({
phenomenon
:
Phenomenon
.
Upostag
,
selectedV
alues
:
[]})];
this
.
getFrequencyAnalysis
().
then
(()
=>
{
this
.
adjustQueryValue
(
this
.
exercise
.
queryItems
[
0
],
0
);
this
.
adjustQueryValue
(
this
.
exercise
.
queryItems
[
1
],
1
);
...
...
@@ -119,10 +121,11 @@ export class CorpusService {
checkAnnisResponse
():
Promise
<
void
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
this
.
annisResponse
)
{
if
(
this
.
annisResponse
&&
this
.
previewAnnisResponse
)
{
return
resolve
();
}
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
state
:
ApplicationState
)
=>
{
this
.
previewAnnisResponse
=
state
.
previewAnnisResponse
;
this
.
annisResponse
=
state
.
mostRecentSetup
.
annisResponse
;
this
.
currentAuthor
=
state
.
mostRecentSetup
.
currentAuthor
;
this
.
currentUrn
=
state
.
mostRecentSetup
.
currentUrn
;
...
...
@@ -215,7 +218,7 @@ export class CorpusService {
getFrequencyAnalysis
():
Promise
<
void
>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
this
.
annisResponse
.
frequency_analysis
.
length
)
{
if
(
this
.
annisResponse
.
frequency_analysis
&&
this
.
annisResponse
.
frequency_analysis
.
length
)
{
return
resolve
();
}
else
{
const
url
:
string
=
configMC
.
backendBaseUrl
+
configMC
.
backendApiFrequencyPath
;
...
...
@@ -234,30 +237,36 @@ export class CorpusService {
});
}
getSortedQueryValues
(
query
:
QueryMC
,
queryIndex
:
number
):
string
[]
{
getSortedQueryValues
(
query
:
QueryMC
,
queryIndex
:
number
):
void
{
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
].
v
alues
[
0
]
&&
x
=>
x
.
values
[
0
]
===
this
.
exercise
.
queryItems
[
0
].
selectedV
alues
[
0
]
&&
x
.
phenomena
[
1
]
===
query
.
phenomenon
);
return
Array
.
from
(
new
Set
<
string
>
(
relevantFIs
.
map
(
x
=>
x
.
values
[
1
]))).
sort
((
a
,
b
)
=>
{
return
pmc
.
translationValues
[
a
]
<
pmc
.
translationValues
[
b
]
?
-
1
:
1
;
});
query
.
availableValues
=
Array
.
from
(
new
Set
<
string
>
(
relevantFIs
.
map
(
x
=>
x
.
values
[
1
])))
.
sort
((
a
,
b
)
=>
{
return
pmc
.
translationValues
[
a
]
<
pmc
.
translationValues
[
b
]
?
-
1
:
1
;
});
return
;
}
else
{
const
relevantFIs
:
FrequencyItem
[]
=
this
.
annisResponse
.
frequency_analysis
.
filter
(
x
=>
x
.
phenomena
[
0
]
===
query
.
phenomenon
);
return
Array
.
from
(
new
Set
<
string
>
(
relevantFIs
.
map
(
x
=>
x
.
values
[
0
]))).
sort
((
a
,
b
)
=>
{
return
pmc
.
translationValues
[
a
]
<
pmc
.
translationValues
[
b
]
?
-
1
:
1
;
});
query
.
availableValues
=
Array
.
from
(
new
Set
<
string
>
(
relevantFIs
.
map
(
x
=>
x
.
values
[
0
])))
.
sort
((
a
,
b
)
=>
{
return
pmc
.
translationValues
[
a
]
<
pmc
.
translationValues
[
b
]
?
-
1
:
1
;
});
return
;
}
}
if
(
!
pmc
.
specificValues
)
{
return
[];
query
.
availableValues
=
[];
return
;
}
return
Object
.
keys
(
pmc
.
specificValues
).
sort
((
a
,
b
)
=>
{
query
.
availableValues
=
Object
.
keys
(
pmc
.
specificValues
).
sort
((
a
,
b
)
=>
{
return
pmc
.
translationValues
[
a
]
<
pmc
.
translationValues
[
b
]
?
-
1
:
1
;
});
return
;
}
getText
(
saveToCache
:
boolean
=
true
):
Promise
<
void
>
{
...
...
@@ -332,8 +341,8 @@ export class CorpusService {
this
.
currentCorpus
=
new
ReplaySubject
<
CorpusMC
>
(
1
);
if
(
!
this
.
currentCorpusCache
)
{
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
state
:
ApplicationState
)
=>
{
const
textData
:
TextData
=
state
.
currentSetup
?
state
.
currentSetup
:
state
.
mostRecentSetup
;
this
.
currentCorpusCache
=
textData
?
textData
.
currentCorpus
:
null
;
this
.
currentCorpusCache
=
state
.
mostRecentSetup
.
currentCorpus
?
state
.
mostRecentSetup
.
currentCorpus
:
null
;
if
(
this
.
currentCorpusCache
)
{
this
.
currentCorpus
.
next
(
this
.
currentCorpusCache
);
}
...
...
@@ -349,7 +358,7 @@ export class CorpusService {
initCurrentTextRange
():
void
{
this
.
currentTextRange
=
new
ReplaySubject
<
TextRange
>
(
1
);
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
state
:
ApplicationState
)
=>
{
this
.
currentTextRangeCache
=
state
.
curr
entSetup
.
currentTextRange
;
this
.
currentTextRangeCache
=
state
.
mostRec
entSetup
.
currentTextRange
;
this
.
currentTextRange
.
next
(
this
.
currentTextRangeCache
);
});
}
...
...
@@ -422,7 +431,6 @@ export class CorpusService {
this
.
annisResponse
=
ar
;
if
(
saveToCache
)
{
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
as
:
ApplicationState
)
=>
{
as
.
currentSetup
.
annisResponse
=
null
;
as
.
mostRecentSetup
=
{
annisResponse
:
ar
,
currentUrn
:
this
.
currentUrn
,
...
...
@@ -430,10 +438,7 @@ export class CorpusService {
currentCorpus
:
this
.
currentCorpusCache
,
currentTextRange
:
this
.
currentTextRangeCache
};
this
.
helperService
.
saveApplicationState
(
as
).
then
(()
=>
{
as
.
currentSetup
.
currentUrn
=
this
.
currentUrn
;
as
.
currentSetup
.
annisResponse
=
ar
;
});
this
.
helperService
.
saveApplicationState
(
as
).
then
();
});
}
}
...
...
@@ -530,7 +535,7 @@ export class CorpusService {
this
.
currentCorpus
.
next
(
this
.
currentCorpusCache
);
this
.
setCurrentTextRange
(
-
1
,
null
,
new
TextRange
({
start
:
[
''
,
''
,
''
],
end
:
[
''
,
''
,
''
]}));
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
state
:
ApplicationState
)
=>
{
state
.
curr
entSetup
.
currentCorpus
=
corpus
;
state
.
mostRec
entSetup
.
currentCorpus
=
corpus
;
this
.
helperService
.
applicationState
.
next
(
state
);
});
}
...
...
@@ -556,9 +561,10 @@ export class CorpusService {
return
;
}
if
(
!
queryIndex
&&
this
.
exercise
.
type
===
ExerciseType
.
matching
)
{
if
(
!
this
.
getSortedQueryValues
(
this
.
exercise
.
queryItems
[
1
],
1
).
length
)
{
this
.
getSortedQueryValues
(
this
.
exercise
.
queryItems
[
1
],
1
);
if
(
!
query
.
selectedValues
.
length
)
{
const
fi
:
FrequencyItem
=
this
.
annisResponse
.
frequency_analysis
.
find
(
x
=>
x
.
values
[
0
]
===
this
.
exercise
.
queryItems
[
0
].
v
alues
[
0
]);
x
=>
x
.
values
[
0
]
===
this
.
exercise
.
queryItems
[
0
].
selectedV
alues
[
0
]);
this
.
exercise
.
queryItems
[
1
].
phenomenon
=
fi
.
phenomena
[
1
];
}
this
.
adjustQueryValue
(
this
.
exercise
.
queryItems
[
1
],
1
);
...
...
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.html
View file @
b98bed42
...
...
@@ -65,9 +65,9 @@
*ngIf=
"corpusService.exercise.type === ExerciseType.matching; else notMatching"
>
<label>
<h2
class=
"label"
>
{{ 'QUERY_VALUE' | translate }}
</h2>
<select
[(ngModel)]=
"query.
v
alues[0]"
name=
"queryValue"
<select
[(ngModel)]=
"query.
selectedV
alues[0]"
name=
"queryValue"
(change)=
"corpusService.updateBaseWord(query, i)"
>
<option
*ngFor=
"let key of
corpusService.getSortedQueryValues(query, i)
"
<option
*ngFor=
"let key of
query.availableValues
"
[value]=
key
>
{{ getDisplayValue(query, key, i) }}
</option>
</select>
...
...
@@ -76,9 +76,9 @@
<ng-template
#notMatching
>
<label>
<h2
class=
"label"
>
{{ 'QUERY_VALUE' | translate }}
</h2>
<select
[(ngModel)]=
"query.
v
alues"
name=
"queryValue"
multiple
size=
"{{Math.min(
corpusService.getSortedQueryValues(query, i)
.length, 20)}}"
>
<option
*ngFor=
"let key of
corpusService.getSortedQueryValues(query, i)
"
<select
[(ngModel)]=
"query.
selectedV
alues"
name=
"queryValue"
multiple
size=
"{{Math.min(
query.availableValues
.length, 20)}}"
>
<option
*ngFor=
"let key of
query.availableValues
"
[value]=
key
>
{{ getDisplayValue(query, key, i) }}
</option>
</select>
...
...
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.spec.ts
View file @
b98bed42
...
...
@@ -70,7 +70,7 @@ describe('ExerciseParametersPage', () => {
configMC
.
maxTextLength
=
0
;
exerciseParametersPage
.
corpusService
.
exercise
.
queryItems
[
0
].
phenomenon
=
Phenomenon
.
Lemma
;
exerciseParametersPage
.
corpusService
.
exercise
.
type
=
ExerciseType
.
matching
;
exerciseParametersPage
.
corpusService
.
exercise
.
queryItems
.
push
(
new
QueryMC
({
v
alues
:
[]}));
exerciseParametersPage
.
corpusService
.
exercise
.
queryItems
.
push
(
new
QueryMC
({
selectedV
alues
:
[]}));
exerciseParametersPage
.
generateExercise
().
then
(()
=>
{
},
()
=>
{
expect
(
h5pSpy
).
toHaveBeenCalledTimes
(
1
);
...
...
mc_frontend/src/app/exercise-parameters/exercise-parameters.page.ts
View file @
b98bed42
...
...
@@ -54,8 +54,9 @@ export class ExerciseParametersPage implements OnInit {
if
(
0
<
configMC
.
maxTextLength
&&
configMC
.
maxTextLength
<
this
.
corpusService
.
currentText
.
length
)
{
this
.
helperService
.
showToast
(
this
.
toastCtrl
,
this
.
corpusService
.
textTooLongString
).
then
();
return
reject
();
}
else
if
((
phenomenon
===
Phenomenon
.
Lemma
&&
!
this
.
corpusService
.
exercise
.
queryItems
[
0
].
values
)
||
this
.
corpusService
.
exercise
.
type
===
ExerciseType
.
matching
&&
!
this
.
corpusService
.
exercise
.
queryItems
[
1
].
values
[
0
])
{
}
else
if
((
phenomenon
===
Phenomenon
.
Lemma
&&
!
this
.
corpusService
.
exercise
.
queryItems
[
0
].
selectedValues
)
||
this
.
corpusService
.
exercise
.
type
===
ExerciseType
.
matching
&&
!
this
.
corpusService
.
exercise
.
queryItems
[
1
].
selectedValues
[
0
])
{
this
.
helperService
.
showToast
(
this
.
toastCtrl
,
this
.
corpusService
.
emptyQueryValueString
).
then
();
return
reject
();
}
else
{
...
...
@@ -74,7 +75,7 @@ export class ExerciseParametersPage implements OnInit {
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
].
v
alues
[
0
]
&&
x
.
values
[
1
]
===
key
);
x
=>
x
.
values
[
0
]
===
this
.
corpusService
.
exercise
.
queryItems
[
0
].
selectedV
alues
[
0
]
&&
x
.
values
[
1
]
===
key
);
count
=
relevantFI
.
count
;
}
else
{
const
relevantFIs
:
FrequencyItem
[]
=
this
.
corpusService
.
annisResponse
.
frequency_analysis
.
filter
(
...
...
@@ -90,7 +91,7 @@ export class ExerciseParametersPage implements OnInit {
getExerciseData
():
Promise
<
void
>
{
return
new
Promise
<
void
>
(
resolve
=>
{
const
searchValues
:
string
[]
=
this
.
corpusService
.
exercise
.
queryItems
.
map
(
query
=>
query
.
phenomenon
+
'
=
'
+
query
.
v
alues
.
join
(
'
|
'
));
query
=>
query
.
phenomenon
+
'
=
'
+
query
.
selectedV
alues
.
join
(
'
|
'
));
let
instructions
:
string
=
this
.
corpusService
.
exercise
.
instructionsTranslation
;
if
(
this
.
corpusService
.
exercise
.
type
===
ExerciseType
.
kwic
)
{
this
.
getKwicExercise
(
JSON
.
stringify
(
searchValues
)).
then
();
...
...
@@ -98,7 +99,7 @@ export class ExerciseParametersPage implements OnInit {
}
else
if
(
this
.
corpusService
.
exercise
.
type
===
ExerciseType
.
markWords
)
{
const
phenomenon
:
Phenomenon
=
this
.
corpusService
.
exercise
.
queryItems
[
0
].
phenomenon
;
const
pmc
:
PhenomenonMapContent
=
this
.
corpusService
.
phenomenonMap
[
phenomenon
];
const
values
:
string
[]
=
this
.
corpusService
.
exercise
.
queryItems
[
0
].
v
alues
as
string
[];
const
values
:
string
[]
=
this
.
corpusService
.
exercise
.
queryItems
[
0
].
selectedV
alues
as
string
[];
instructions
+=
` [
${
values
.
map
(
x
=>
pmc
.
translationValues
[
x
]).
join
(
'
,
'
)}
]`
;
}
this
.
corpusService
.
currentCorpus
.
pipe
(
take
(
1
)).
subscribe
((
cc
:
CorpusMC
)
=>
{
...
...
@@ -135,14 +136,12 @@ export class ExerciseParametersPage implements OnInit {
formData
.
append
(
key
,
ef
[
key
]);
});
this
.
helperService
.
makePostRequest
(
this
.
http
,
this
.
toastCtrl
,
url
,
formData
).
then
((
ar
:
AnnisResponse
)
=>
{
// 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
;
this
.
helperService
.
applicationState
.
pipe
(
take
(
1
)).
subscribe
((
as
:
ApplicationState
)
=>
{
as
.
mostRecentSetup
.
a
nnisResponse
=
ar
;
as
.
previewAnnisResponse
=
this
.
corpusService
.
previewA
nnisResponse
=
ar
;
this
.
helperService
.
saveApplicationState
(
as
).
then
();
this
.
corpusService
.
annisResponse
.
exercise_id
=
ar
.
exercise_id
;
this
.
corpusService
.
annisResponse
.
uri
=
ar
.
uri
;
this
.
corpusService
.
annisResponse
.
solutions
=
ar
.
solutions
;
//
this.corpusService.annisResponse.exercise_id = ar.exercise_id;
//
this.corpusService.annisResponse.uri = ar.uri;
//
this.corpusService.annisResponse.solutions = ar.solutions;
this
.
helperService
.
goToPage
(
this
.
navCtrl
,
configMC
.
pageUrlPreview
).
then
();
return
resolve
();
});
...
...
mc_frontend/src/app/exercise.service.spec.ts
View file @
b98bed42
...
...
@@ -89,13 +89,13 @@ describe('ExerciseService', () => {
expect
(
postSpy
).
toHaveBeenCalledTimes
(
0
);
exerciseService
.
currentExerciseParams
=
{};
const
downloadSpy
:
Spy
=
spyOn
(
exerciseService
,
'
downloadBlobAsFile
'
);
exerciseService
.
corpusService
.
a
nnisResponse
=
{
exercise_id
:
''
};
exerciseService
.
corpusService
.
previewA
nnisResponse
=
{
exercise_id
:
''
};
exerciseService
.
corpusService
.
exercise
.
type
=
ExerciseType
.
markWords
;
exerciseService
.
currentExerciseParams
=
{
language
:
LanguageShortcut
.
English
};
exerciseService
.
downloadH5Pexercise
().
then
(()
=>
{
expect
(
downloadSpy
).
toHaveBeenCalledTimes
(
1
);
exerciseService
.
corpusService
.
currentSolutions
=
exerciseService
.
corpusService
.
a
nnisResponse
.
solutions
=
[{
exerciseService
.
corpusService
.
previewA
nnisResponse
.
solutions
=
[{
target
:
{
token_id
:
1
,
sentence_id
:
1
...
...
@@ -167,7 +167,7 @@ describe('ExerciseService', () => {
it
(
'
should get solution indices
'
,
()
=>
{