diff --git a/inception/inception-active-learning/src/main/java/de/tudarmstadt/ukp/inception/active/learning/ActiveLearningServiceImpl.java b/inception/inception-active-learning/src/main/java/de/tudarmstadt/ukp/inception/active/learning/ActiveLearningServiceImpl.java index dde3c5973cd..cf08e6f2fa8 100644 --- a/inception/inception-active-learning/src/main/java/de/tudarmstadt/ukp/inception/active/learning/ActiveLearningServiceImpl.java +++ b/inception/inception-active-learning/src/main/java/de/tudarmstadt/ukp/inception/active/learning/ActiveLearningServiceImpl.java @@ -175,7 +175,8 @@ public Optional> generateNextSuggestion(String aSessionOwn var pref = recommendationService.getPreferences(aDataOwner, alState.getLayer().getProject()); var nextSuggestion = alState.getStrategy().generateNextSuggestion(pref, suggestionGroups); - assert nextSuggestion.get().getFirst().isVisible() : "Generated suggestion must be visible"; + assert !nextSuggestion.isPresent() || nextSuggestion.get().getFirst() + .isVisible() : "Generated suggestion must be visible"; return nextSuggestion; } @@ -214,8 +215,8 @@ public void acceptSpanSuggestion(SourceDocument aDocument, User aDataOwner, aSuggestion, suggestionWithUserSelectedLabel, AL_SIDEBAR); } else { - recommendationService.acceptSuggestion(sessionOwner, aDocument, dataOwner, cas, suggestionWithUserSelectedLabel, - AL_SIDEBAR); + recommendationService.acceptSuggestion(sessionOwner, aDocument, dataOwner, cas, + suggestionWithUserSelectedLabel, AL_SIDEBAR); } // Save CAS after annotation has been created diff --git a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatMetadataRecommenderFactory.java b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatMetadataRecommenderFactory.java index 9719cec03c8..ca92dfa1b60 100644 --- a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatMetadataRecommenderFactory.java +++ b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatMetadataRecommenderFactory.java @@ -23,7 +23,6 @@ import org.apache.uima.cas.CAS; import org.apache.wicket.model.IModel; -import org.springframework.stereotype.Component; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; @@ -32,7 +31,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngineFactoryImplBase; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSupport; -@Component public class OpenNlpDoccatMetadataRecommenderFactory extends RecommendationEngineFactoryImplBase { diff --git a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatRecommenderFactory.java b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatRecommenderFactory.java index 0d183ea8f8a..166b4b4923c 100644 --- a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatRecommenderFactory.java +++ b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/OpenNlpDoccatRecommenderFactory.java @@ -25,7 +25,6 @@ import org.apache.uima.cas.CAS; import org.apache.wicket.model.IModel; -import org.springframework.stereotype.Component; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; @@ -34,7 +33,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngine; import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngineFactoryImplBase; -@Component public class OpenNlpDoccatRecommenderFactory extends RecommendationEngineFactoryImplBase { diff --git a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/config/OpenNlpRecommenderAutoConfiguration.java b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/config/OpenNlpRecommenderAutoConfiguration.java new file mode 100644 index 00000000000..b63304480e7 --- /dev/null +++ b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/doccat/config/OpenNlpRecommenderAutoConfiguration.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Technische Universität Darmstadt under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The Technische Universität Darmstadt + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.doccat.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.doccat.OpenNlpDoccatMetadataRecommenderFactory; +import de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.doccat.OpenNlpDoccatRecommenderFactory; +import de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.ner.OpenNlpNerRecommenderFactory; +import de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.pos.OpenNlpPosRecommenderFactory; +import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; + +@Configuration +public class OpenNlpRecommenderAutoConfiguration +{ + @Bean + public OpenNlpDoccatRecommenderFactory openNlpDoccatRecommenderFactory() + { + return new OpenNlpDoccatRecommenderFactory(); + } + + @Bean + @ConditionalOnProperty(prefix = "documentmetadata", name = "enabled", havingValue = "true", matchIfMissing = true) + public OpenNlpDoccatMetadataRecommenderFactory openNlpDoccatMetadataRecommenderFactory( + AnnotationSchemaService aSchemaService) + { + return new OpenNlpDoccatMetadataRecommenderFactory(); + } + + @Bean + public OpenNlpNerRecommenderFactory openNlpNerRecommenderFactory() + { + return new OpenNlpNerRecommenderFactory(); + } + + @Bean + public OpenNlpPosRecommenderFactory openNlpPosRecommenderFactory() + { + return new OpenNlpPosRecommenderFactory(); + } +} diff --git a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/ner/OpenNlpNerRecommenderFactory.java b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/ner/OpenNlpNerRecommenderFactory.java index 338ab3dc5ef..8a2f1578dd8 100644 --- a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/ner/OpenNlpNerRecommenderFactory.java +++ b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/ner/OpenNlpNerRecommenderFactory.java @@ -27,7 +27,6 @@ import static java.util.Arrays.asList; import org.apache.uima.cas.CAS; -import org.springframework.stereotype.Component; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; @@ -35,7 +34,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngine; import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngineFactoryImplBase; -@Component public class OpenNlpNerRecommenderFactory extends RecommendationEngineFactoryImplBase { diff --git a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/pos/OpenNlpPosRecommenderFactory.java b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/pos/OpenNlpPosRecommenderFactory.java index 32a0ab17ea3..24a68cf3ed6 100644 --- a/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/pos/OpenNlpPosRecommenderFactory.java +++ b/inception/inception-imls-opennlp/src/main/java/de/tudarmstadt/ukp/inception/recommendation/imls/opennlp/pos/OpenNlpPosRecommenderFactory.java @@ -26,7 +26,6 @@ import org.apache.uima.cas.CAS; import org.apache.wicket.model.IModel; -import org.springframework.stereotype.Component; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; @@ -35,7 +34,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngine; import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngineFactoryImplBase; -@Component public class OpenNlpPosRecommenderFactory extends RecommendationEngineFactoryImplBase { diff --git a/inception/inception-imls-opennlp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/inception/inception-imls-opennlp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..9fcdb3576de --- /dev/null +++ b/inception/inception-imls-opennlp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +de.tudarmstadt.ukp.inception.recommendation.imls.opennlp.doccat.config.OpenNlpRecommenderAutoConfiguration diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.html b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.html index e3ae368c3ca..f8b7f2a58f1 100644 --- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.html +++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.html @@ -46,7 +46,7 @@
-
+
diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.java b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.java index 3cb840f6fa8..1b4ba3e0a45 100644 --- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.java +++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataAnnotationSelectionPanel.java @@ -19,6 +19,7 @@ import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.EXTENSION_ID; import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordChangeLocation.MAIN_EDITOR; +import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CHANGE_EVENT; import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CLICK; import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.enabledWhen; import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhen; @@ -63,16 +64,13 @@ import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasProvider; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; -import de.tudarmstadt.ukp.clarin.webanno.model.Project; -import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; -import de.tudarmstadt.ukp.clarin.webanno.security.model.User; import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage; import de.tudarmstadt.ukp.inception.annotation.events.FeatureValueUpdatedEvent; import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler; -import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.event.AjaxRecommendationAcceptedEvent; +import de.tudarmstadt.ukp.inception.recommendation.api.event.AjaxRecommendationRejectedEvent; import de.tudarmstadt.ukp.inception.recommendation.api.model.MetadataSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionDocumentGroup; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; @@ -81,19 +79,17 @@ import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.api.feature.FeatureSupportRegistry; import de.tudarmstadt.ukp.inception.schema.api.feature.TypeUtil; -import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupport; import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupportRegistry; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxEventBehavior; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormComponentUpdatingBehavior; import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxLink; -import de.tudarmstadt.ukp.inception.support.spring.ApplicationEventPublisherHolder; import de.tudarmstadt.ukp.inception.support.uima.ICasUtil; import de.tudarmstadt.ukp.inception.ui.core.docanno.event.DocumentMetadataEvent; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerAdapter; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSupport; public class DocumentMetadataAnnotationSelectionPanel - extends GenericPanel + extends GenericPanel { private static final long serialVersionUID = 8318858582025740458L; @@ -101,58 +97,54 @@ public class DocumentMetadataAnnotationSelectionPanel private static final String CID_LABEL = "label"; private static final String CID_SCORE = "score"; + private static final String CID_LAYER = "layer"; private static final String CID_LAYERS = "layers"; + private static final String CID_LAYERS_CONTAINER = "layersContainer"; + private static final String CID_ANNOTATION = "annotation"; private static final String CID_ANNOTATIONS = "annotations"; - private static final String CID_LAYER = "layer"; - private static final String CID_CREATE = "create"; private static final String CID_ANNOTATIONS_CONTAINER = "annotationsContainer"; private static final String CID_ANNOTATION_DETAILS = "annotationDetails"; + private static final String CID_NO_LAYERS_WARNING = "noLayersWarning"; + private static final String CID_CREATE = "create"; private static final String CID_DELETE = "delete"; private static final String CID_ACCEPT = "accept"; private static final String CID_REJECT = "reject"; + private static final String CID_OPEN = "open"; + private static final String CID_CLOSE = "close"; private @SpringBean LayerSupportRegistry layerSupportRegistry; private @SpringBean FeatureSupportRegistry fsRegistry; private @SpringBean AnnotationSchemaService annotationService; private @SpringBean RecommendationService recommendationService; - private @SpringBean LearningRecordService learningRecordService; private @SpringBean UserDao userService; - private @SpringBean ApplicationEventPublisherHolder applicationEventPublisherHolder; private final AnnotationPage annotationPage; - private final CasProvider jcasProvider; - private final IModel sourceDocument; - private final IModel user; - private final IModel selectedLayer; + private final CasProvider casProvider; private final AnnotationActionHandler actionHandler; + private final WebMarkupContainer layersContainer; + + private final IModel selectedLayer; + private final IModel> layers; + private WebMarkupContainer selectedAnnotation; - private WebMarkupContainer layersContainer; private DocumentMetadataAnnotationDetailPanel selectedDetailPanel; private int createdAnnotationAddress; - private final IModel state; - - private final IModel> layers; public DocumentMetadataAnnotationSelectionPanel(String aId, CasProvider aCasProvider, AnnotationPage aAnnotationPage, AnnotationActionHandler aActionHandler, IModel aState) { - super(aId, aState.map(AnnotatorState::getProject)); + super(aId, aState); setOutputMarkupPlaceholderTag(true); - state = aState; - - sourceDocument = aState.map(AnnotatorState::getDocument); - user = aState.map(AnnotatorState::getUser); - annotationPage = aAnnotationPage; - jcasProvider = aCasProvider; - selectedLayer = Model.of(listCreatableMetadataLayers().stream().findFirst().orElse(null)); - var availableLayers = LoadableDetachableModel.of(this::listCreatableMetadataLayers); + casProvider = aCasProvider; actionHandler = aActionHandler; + selectedLayer = Model.of(listCreatableMetadataLayers().stream().findFirst().orElse(null)); layers = LoadableDetachableModel.of(this::listLayers); + var availableLayers = LoadableDetachableModel.of(this::listCreatableMetadataLayers); var content = new WebMarkupContainer("content"); add(content); @@ -161,7 +153,7 @@ public DocumentMetadataAnnotationSelectionPanel(String aId, CasProvider aCasProv layer.setModel(selectedLayer); layer.setChoices(availableLayers); layer.setChoiceRenderer(new ChoiceRenderer<>("uiName")); - layer.add(new LambdaAjaxFormComponentUpdatingBehavior("change")); + layer.add(new LambdaAjaxFormComponentUpdatingBehavior(CHANGE_EVENT)); layer.add(visibleWhen(() -> !availableLayers.map(List::isEmpty).orElse(true).getObject())); content.add(layer); @@ -169,49 +161,68 @@ public DocumentMetadataAnnotationSelectionPanel(String aId, CasProvider aCasProv .add(enabledWhen(() -> annotationPage.isEditable())) // .add(visibleWhenNot(availableLayers.map(List::isEmpty).orElse(true)))); - layersContainer = new WebMarkupContainer("layersContainer"); + layersContainer = new WebMarkupContainer(CID_LAYERS_CONTAINER); layersContainer.setOutputMarkupPlaceholderTag(true); layersContainer.add(createLayerGroupList()); layersContainer.add(visibleWhenNot(availableLayers.map(List::isEmpty).orElse(true))); content.add(layersContainer); - var noLayersWarning = new WebMarkupContainer("noLayersWarning"); - noLayersWarning.add(visibleWhen(availableLayers.map(List::isEmpty).orElse(true))); - add(noLayersWarning); + add(new WebMarkupContainer(CID_NO_LAYERS_WARNING) + .add(visibleWhen(availableLayers.map(List::isEmpty).orElse(true)))); } private void actionAccept(AjaxRequestTarget aTarget, AnnotationListItem aItem) { try { + annotationPage.ensureIsEditable(); + var page = (AnnotationPage) aTarget.getPage(); - var dataOwner = state.getObject().getUser().getUsername(); + var state = getModelObject(); + var dataOwner = state.getUser().getUsername(); var sessionOwner = userService.getCurrentUser(); - var suggestion = (MetadataSuggestion) recommendationService - .getPredictions(sessionOwner, state.getObject().getProject()) - .getPredictionByVID(state.getObject().getDocument(), aItem.vid).get(); + var suggestion = recommendationService.getPredictions(sessionOwner, state.getProject()) + .getPredictionByVID(state.getDocument(), aItem.vid).get(); - var aCas = jcasProvider.get(); + var aCas = casProvider.get(); - var annotation = recommendationService.acceptSuggestion(sessionOwner.getUsername(), - state.getObject().getDocument(), dataOwner, aCas, suggestion, MAIN_EDITOR); + recommendationService.acceptSuggestion(sessionOwner.getUsername(), state.getDocument(), + dataOwner, aCas, suggestion, MAIN_EDITOR); page.writeEditorCas(aCas); - // Set selection to the accepted annotation and select it and load it into the detail - // editor - // state.getObject().getSelection().set(adapter.select(VID.of(annotation), annotation)); - - // Send a UI event that the suggestion has been accepted page.send(page, BREADTH, - new AjaxRecommendationAcceptedEvent(aTarget, state.getObject(), aItem.vid)); + new AjaxRecommendationAcceptedEvent(aTarget, state, aItem.vid)); } catch (Exception e) { handleException(this, aTarget, e); } } - private void actionReject(AjaxRequestTarget a$, AnnotationListItem aAnnotationListItem) + private void actionReject(AjaxRequestTarget aTarget, AnnotationListItem aItem) { + try { + annotationPage.ensureIsEditable(); + + var page = (AnnotationPage) aTarget.getPage(); + var state = getModelObject(); + var dataOwner = state.getUser().getUsername(); + var sessionOwner = userService.getCurrentUser(); + var suggestion = recommendationService.getPredictions(sessionOwner, state.getProject()) + .getPredictionByVID(state.getDocument(), aItem.vid).get(); + + var aCas = casProvider.get(); + + recommendationService.rejectSuggestion(sessionOwner.getUsername(), state.getDocument(), + dataOwner, suggestion, MAIN_EDITOR); + + page.writeEditorCas(aCas); + + page.send(page, BREADTH, + new AjaxRecommendationRejectedEvent(aTarget, state, aItem.vid)); + } + catch (Exception e) { + handleException(this, aTarget, e); + } } private void actionCreate(AjaxRequestTarget aTarget) throws AnnotationException, IOException @@ -219,10 +230,11 @@ private void actionCreate(AjaxRequestTarget aTarget) throws AnnotationException, try { annotationPage.ensureIsEditable(); + var state = getModelObject(); var adapter = (DocumentMetadataLayerAdapter) annotationService .getAdapter(selectedLayer.getObject()); - var cas = jcasProvider.get(); - var fs = adapter.add(sourceDocument.getObject(), user.getObject().getUsername(), cas); + var cas = casProvider.get(); + var fs = adapter.add(state.getDocument(), state.getUser().getUsername(), cas); createdAnnotationAddress = fs.getAddress(); annotationPage.writeEditorCas(cas); @@ -243,15 +255,13 @@ private void actionDelete(AjaxRequestTarget aTarget, annotationPage.ensureIsEditable(); // Load the boiler-plate - var project = getModelObject(); - var cas = jcasProvider.get(); + var state = getModelObject(); + var cas = casProvider.get(); var fs = ICasUtil.selectFsByAddr(cas, aDetailPanel.getModelObject().getId()); - var layer = annotationService.findLayer(project, fs); - var adapter = annotationService.getAdapter(layer); + var adapter = annotationService.findAdapter(state.getProject(), fs); // Perform actual actions - adapter.delete(sourceDocument.getObject(), user.getObject().getUsername(), cas, - VID.of(fs)); + adapter.delete(state.getDocument(), state.getUser().getUsername(), cas, VID.of(fs)); // persist changes annotationPage.writeEditorCas(cas); @@ -260,6 +270,7 @@ private void actionDelete(AjaxRequestTarget aTarget, selectedAnnotation = null; selectedDetailPanel = null; } + remove(aDetailPanel); annotationPage.actionRefreshDocument(aTarget); @@ -317,11 +328,11 @@ protected void populateItem(ListItem aItem) aItem.add(new Label("layerName", aItem.getModelObject().layer.getUiName())); - var annotationsContainer = new WebMarkupContainer(CID_ANNOTATIONS_CONTAINER); - annotationsContainer.setOutputMarkupPlaceholderTag(true); - annotationsContainer.add(createAnnotationList(annotations)); - annotationsContainer.add(visibleWhen(() -> !availableLayers.isEmpty())); - aItem.add(annotationsContainer); + var container = new WebMarkupContainer(CID_ANNOTATIONS_CONTAINER); + container.setOutputMarkupPlaceholderTag(true); + container.add(createAnnotationList(annotations)); + container.add(visibleWhen(() -> !availableLayers.isEmpty())); + aItem.add(container); } }; @@ -341,11 +352,13 @@ protected void populateItem(ListItem aItem) var vid = aItem.getModelObject().vid; - var container = new WebMarkupContainer("annotation"); + var container = new WebMarkupContainer(CID_ANNOTATION); + container.add(visibleWhen(() -> !aItem.getModelObject().singleton)); aItem.add(container); var detailPanel = new DocumentMetadataAnnotationDetailPanel(CID_ANNOTATION_DETAILS, - Model.of(vid), jcasProvider, annotationPage, actionHandler, state); + Model.of(vid), casProvider, annotationPage, actionHandler, + DocumentMetadataAnnotationSelectionPanel.this.getModel()); aItem.add(detailPanel); var isSuggestion = EXTENSION_ID.equals(aItem.getModelObject().vid.getExtensionId()); @@ -363,12 +376,12 @@ protected void populateItem(ListItem aItem) selectedDetailPanel = detailPanel; } - var close = new WebMarkupContainer("close"); + var close = new WebMarkupContainer(CID_CLOSE); close.add(visibleWhen(() -> isExpanded(aItem, container) && !isSuggestion)); close.setOutputMarkupId(true); container.add(close); - var open = new WebMarkupContainer("open"); + var open = new WebMarkupContainer(CID_OPEN); open.add(visibleWhen(() -> !isExpanded(aItem, container) && !isSuggestion)); open.setOutputMarkupId(true); container.add(open); @@ -413,7 +426,7 @@ private boolean isExpanded(ListItem aItem, private List listMetadataLayers() { - return annotationService.listAnnotationLayer(getModelObject()).stream() + return annotationService.listAnnotationLayer(getModelObject().getProject()).stream() .filter(layer -> DocumentMetadataLayerSupport.TYPE.equals(layer.getType()) && layer.isEnabled()) // .toList(); @@ -441,49 +454,59 @@ private List listAnnotations(AnnotationLayer aLayer) { CAS cas; try { - cas = jcasProvider.get(); + cas = casProvider.get(); } catch (IOException e) { LOG.error("Unable to load CAS", e); return emptyList(); } - var items = new ArrayList(); - - // --- Populate with annotations --- - // Bulk-load all the features of this layer to avoid having to do repeated DB accesses // later var features = annotationService.listSupportedFeatures(aLayer); - var featuresIndex = features.stream() - .collect(toMap(AnnotationFeature::getName, identity())); + var layerSupport = getLayerSupport(aLayer); + var singleton = layerSupport.readTraits(aLayer).isSingleton(); + + var items = new ArrayList(); + generateAnnotationItems(aLayer, layerSupport, singleton, cas, items, features); + generateSuggestionItems(aLayer, layerSupport, singleton, cas, items, features); + return items; + } + + private void generateAnnotationItems(AnnotationLayer aLayer, + DocumentMetadataLayerSupport layerSupport, boolean singleton, CAS cas, + ArrayList items, List features) + { var adapter = annotationService.getAdapter(aLayer); - LayerSupport layerSupport = layerSupportRegistry.getLayerSupport(aLayer); var renderer = layerSupport.createRenderer(aLayer, () -> annotationService.listAnnotationFeature(aLayer)); - var singleton = getLayerSupport(aLayer).readTraits(aLayer).isSingleton(); for (var fs : cas.select(adapter.getAnnotationType(cas))) { var renderedFeatures = renderer.renderLabelFeatureValues(adapter, fs, features); var labelText = TypeUtil.getUiLabelText(renderedFeatures); items.add(new AnnotationListItem(VID.of(fs), labelText, aLayer, singleton, 0.0d)); } + } - // --- Populate with predictions --- - var predictions = recommendationService.getPredictions(user.getObject(), getModelObject()); + private void generateSuggestionItems(AnnotationLayer aLayer, + DocumentMetadataLayerSupport layerSupport, boolean singleton, CAS cas, + ArrayList items, List features) + { + var state = getModelObject(); + var featuresIndex = features.stream() + .collect(toMap(AnnotationFeature::getName, identity())); + var predictions = recommendationService.getPredictions(state.getUser(), state.getProject()); if (predictions != null) { var predictionsByDocument = predictions - .getPredictionsByDocument(sourceDocument.getObject().getName()); + .getPredictionsByDocument(state.getDocument().getName()); var group = SuggestionDocumentGroup.groupsOfType(MetadataSuggestion.class, predictionsByDocument); recommendationService.calculateSuggestionVisibility(userService.getCurrentUsername(), - state.getObject().getDocument(), cas, state.getObject().getUser().getUsername(), - aLayer, group, -1, -1); + state.getDocument(), cas, state.getUser().getUsername(), aLayer, group, -1, -1); - var pref = recommendationService.getPreferences(state.getObject().getUser(), - state.getObject().getProject()); + var pref = recommendationService.getPreferences(state.getUser(), state.getProject()); for (var suggestion : predictionsByDocument) { if ((!suggestion.isVisible() && !pref.isShowAllPredictions()) @@ -503,8 +526,6 @@ private List listAnnotations(AnnotationLayer aLayer) } } } - - return items; } @OnEvent @@ -553,38 +574,12 @@ protected static void handleException(Component aComponent, AjaxRequestTarget aT } } - private class LayerGroup + private record LayerGroup(AnnotationLayer layer) implements Serializable - { - private static final long serialVersionUID = -1798740501968780059L; - - final AnnotationLayer layer; - - public LayerGroup(AnnotationLayer aLayer) - { - layer = aLayer; - } - } + {} - private class AnnotationListItem + private record AnnotationListItem(VID vid, String label, AnnotationLayer layer, + boolean singleton, double score) implements Serializable - { - private static final long serialVersionUID = -8505492366690693091L; - - final VID vid; - final String label; - final AnnotationLayer layer; - final boolean singleton; - final double score; - - public AnnotationListItem(VID aVid, String aLabel, AnnotationLayer aLayer, - boolean aSingleton, double aScore) - { - vid = aVid; - label = aLabel; - layer = aLayer; - singleton = aSingleton; - score = aScore; - } - } + {} } diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java index 752e1ff7e57..54e2830593b 100644 --- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java +++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java @@ -19,10 +19,13 @@ import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_ALL; import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_OVERLAP; +import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_TRANSIENT_REJECTED; +import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.REJECTED; import java.lang.invoke.MethodHandles; import java.util.Collection; import java.util.List; +import java.util.Objects; import org.apache.commons.lang3.NotImplementedException; import org.apache.uima.cas.AnnotationBaseFS; @@ -39,6 +42,7 @@ import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupport_ImplBase; +import de.tudarmstadt.ukp.inception.recommendation.api.event.RecommendationRejectedEvent; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecord; import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordChangeLocation; @@ -121,7 +125,21 @@ public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, Str AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction) throws AnnotationException { - throw new NotImplementedException("Not yet implemented"); + var suggestion = (MetadataSuggestion) aSuggestion; + + // Hide the suggestion. This is faster than having to recalculate the visibility status + // for the entire document or even for the part visible on screen. + suggestion.hide(FLAG_TRANSIENT_REJECTED); + + var recommender = recommendationService.getRecommender(suggestion); + var feature = recommender.getFeature(); + // Log the action to the learning record + learningRecordService.logRecord(aSessionOwner, aDocument, aDataOwner, suggestion, feature, + REJECTED, aAction); + + // Send an application event that the suggestion has been rejected + applicationEventPublisher.publishEvent(new RecommendationRejectedEvent(this, aDocument, + aDataOwner, feature, suggestion.getLabel())); } @Override @@ -158,6 +176,8 @@ public void calculateSuggestionVisibility(Strin var recordedAnnotations = learningRecordService.listLearningRecords(aSessionOwner, aDataOwner, aLayer); + var adapter = schemaService.getAdapter(aLayer); + var traits = adapter.getTraits(DocumentMetadataLayerTraits.class).get(); for (var feature : schemaService.listSupportedFeatures(aLayer)) { var feat = type.getFeatureByBaseName(feature.getName()); @@ -178,25 +198,22 @@ public void calculateSuggestionVisibility(Strin }) // .toList(); - hideSpanSuggestionsThatMatchAnnotations(annotations, feature, feat, - suggestionsForFeature); + hideSpanSuggestionsThatMatchAnnotations(traits.isSingleton(), annotations, feature, + feat, suggestionsForFeature); - // // Anything that was not hidden so far might still have been rejected - // suggestionsForFeature.stream() // - // .flatMap(SuggestionGroup::stream) // - // .filter(AnnotationSuggestion::isVisible) // - // .forEach(suggestion -> hideSuggestionsRejectedOrSkipped(suggestion, - // recordedAnnotations)); + // Anything that was not hidden so far might still have been rejected + suggestionsForFeature.stream() // + .flatMap(SuggestionGroup::stream) // + .filter(AnnotationSuggestion::isVisible) // + .forEach(suggestion -> hideSuggestionsRejectedOrSkipped(suggestion, + recordedAnnotations)); } } - private void hideSpanSuggestionsThatMatchAnnotations(List aAnnotations, - AnnotationFeature aFeature, Feature aFeat, + private void hideSpanSuggestionsThatMatchAnnotations(boolean singleton, + List aAnnotations, AnnotationFeature aFeature, Feature aFeat, List> aSuggestionsForFeature) { - var layer = aFeature.getLayer(); - var adapter = schemaService.getAdapter(layer); - var traits = adapter.getTraits(DocumentMetadataLayerTraits.class); for (var annotation : aAnnotations) { var label = annotation.getFeatureValueAsString(aFeat); @@ -206,7 +223,7 @@ private void hideSpanSuggestionsThatMatchAnnotations(List aAnnot } for (var sugGroup : aSuggestionsForFeature) { - if (traits.get().isSingleton()) { + if (singleton) { sugGroup.hideAll(FLAG_OVERLAP); } else { @@ -220,6 +237,20 @@ private void hideSpanSuggestionsThatMatchAnnotations(List aAnnot } } + static void hideSuggestionsRejectedOrSkipped(MetadataSuggestion aSuggestion, + List aRecordedRecommendations) + { + aRecordedRecommendations.stream() // + .filter(r -> Objects.equals(r.getLayer().getId(), aSuggestion.getLayerId())) // + .filter(r -> Objects.equals(r.getAnnotationFeature().getName(), + aSuggestion.getFeature())) // + .filter(r -> Objects.equals(r.getSourceDocument().getName(), + aSuggestion.getDocumentName())) // + .filter(r -> aSuggestion.labelEquals(r.getAnnotation())) // + .filter(r -> aSuggestion.hideSuggestion(r.getUserAction())) // + .findAny(); + } + @Override public LearningRecord toLearningRecord(SourceDocument aDocument, String aUsername, AnnotationSuggestion aSuggestion, AnnotationFeature aFeature, diff --git a/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring.factories b/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring.factories deleted file mode 100644 index d3ef3ca5273..00000000000 --- a/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -de.tudarmstadt.ukp.inception.ui.core.docanno.config.DocumentMetadataLayerSupportAutoConfiguration \ No newline at end of file diff --git a/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..5d3da1a15cf --- /dev/null +++ b/inception/inception-layer-docmetadata/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +de.tudarmstadt.ukp.inception.ui.core.docanno.config.DocumentMetadataLayerSupportAutoConfiguration diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommendationService.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommendationService.java index e68efceb2b4..8c8d4c25f55 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommendationService.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommendationService.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Optional; +import org.apache.uima.cas.AnnotationBaseFS; import org.apache.uima.cas.CAS; import org.apache.uima.cas.text.AnnotationFS; @@ -68,6 +69,8 @@ public interface RecommendationService Recommender getRecommender(long aId); + Recommender getRecommender(AnnotationSuggestion aSuggestion); + Optional getRecommender(Project aProject, String aName); boolean existsRecommender(Project aProject, String aName); @@ -199,8 +202,9 @@ AnnotationFS correctSuggestion(String aSessionOwner, SourceDocument aDocument, * @throws AnnotationException * if there was an annotation-level problem */ - AnnotationFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner, - CAS aCas, AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation) + AnnotationBaseFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument, + String aDataOwner, CAS aCas, AnnotationSuggestion aSuggestion, + LearningRecordChangeLocation aLocation) throws AnnotationException; /** diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/event/RecommendationRejectedEvent.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/event/RecommendationRejectedEvent.java index c6a415c39b7..c60f9aa223a 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/event/RecommendationRejectedEvent.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/event/RecommendationRejectedEvent.java @@ -36,6 +36,12 @@ public class RecommendationRejectedEvent private final AnnotationFeature feature; private final Object recommendedValue; + public RecommendationRejectedEvent(Object aSource, SourceDocument aDocument, String aUser, + AnnotationFeature aFeature, Object aRecommendedValue) + { + this(aSource, aDocument, aUser, -1, -1, null, aFeature, aRecommendedValue); + } + public RecommendationRejectedEvent(Object aSource, SourceDocument aDocument, String aUser, int aBegin, int aEnd, String aText, AnnotationFeature aFeature, Object aRecommendedValue) diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java index 80e2c7f8780..62c880a75df 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java @@ -34,6 +34,7 @@ import java.util.Optional; import org.apache.uima.cas.CAS; +import org.apache.uima.jcas.tcas.Annotation; import org.apache.wicket.Page; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.feedback.IFeedback; @@ -219,11 +220,10 @@ private void actionAcceptSpanRecommendation(AjaxRequestTarget aTarget, var dataOwner = aState.getUser().getUsername(); var sessionOwner = userService.getCurrentUsername(); var layer = annotationService.getLayer(aSuggestion.getLayerId()); - var feature = annotationService.getFeature(aSuggestion.getFeature(), layer); var adapter = (SpanAdapter) annotationService.getAdapter(layer); - var span = recommendationService.acceptSuggestion(sessionOwner, aSocument, dataOwner, aCas, - aSuggestion, MAIN_EDITOR); + var span = (Annotation) recommendationService.acceptSuggestion(sessionOwner, aSocument, + dataOwner, aCas, aSuggestion, MAIN_EDITOR); page.writeEditorCas(aCas); @@ -246,8 +246,8 @@ private void actionAcceptRelationRecommendation(AjaxRequestTarget aTarget, var layer = annotationService.getLayer(aSuggestion.getLayerId()); var adapter = (RelationAdapter) annotationService.getAdapter(layer); - var relation = recommendationService.acceptSuggestion(sessionOwner, aDocument, dataOwner, - aCas, aSuggestion, MAIN_EDITOR); + var relation = (Annotation) recommendationService.acceptSuggestion(sessionOwner, aDocument, + dataOwner, aCas, aSuggestion, MAIN_EDITOR); page.writeEditorCas(aCas); diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/project/RecommenderEditorPanel.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/project/RecommenderEditorPanel.java index 46538e0e7f6..ce2a39b0110 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/project/RecommenderEditorPanel.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/project/RecommenderEditorPanel.java @@ -18,8 +18,7 @@ package de.tudarmstadt.ukp.inception.recommendation.project; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.MAX_RECOMMENDATIONS_CAP; -import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.RELATION_TYPE; -import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.SPAN_TYPE; +import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CHANGE_EVENT; import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhen; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -61,6 +60,8 @@ import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; +import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationLayerSupport; +import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommenderFactoryRegistry; import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender; @@ -153,7 +154,7 @@ public RecommenderEditorPanel(String aId, IModel aProject, layerChoice.setChoiceRenderer(new ChoiceRenderer<>("uiName")); layerChoice.setRequired(true); // The features and tools depend on the layer, so reload them when the layer is changed - layerChoice.add(new LambdaAjaxFormComponentUpdatingBehavior("change", t -> { + layerChoice.add(new LambdaAjaxFormComponentUpdatingBehavior(CHANGE_EVENT, t -> { toolChoice.setModelObject(null); featureChoice.setModelObject(null); autoUpdateName(t, nameField, recommenderModel.getObject()); @@ -407,12 +408,12 @@ protected void onModelChanged() private List listLayers() { return annotationSchemaService.listAnnotationLayer(projectModel.getObject()).stream() // - .filter(layer -> (!SPAN_TYPE.equals(layer.getType()) - || RELATION_TYPE.equals(layer.getType()) // + .filter(layer -> (SpanLayerSupport.TYPE.equals(layer.getType()) + || RelationLayerSupport.TYPE.equals(layer.getType()) // || DocumentMetadataLayerSupport.TYPE.equals(layer.getType())) // && !(Token._TypeName.equals(layer.getName()) || Sentence._TypeName.equals(layer.getName()))) - .collect(toList()); + .toList(); } private List listFeatures() @@ -421,7 +422,7 @@ private List listFeatures() return emptyList(); } - AnnotationLayer layer = recommenderModel.getObject().getLayer(); + var layer = recommenderModel.getObject().getLayer(); if (layer == null) { return emptyList(); } @@ -437,8 +438,8 @@ private List> listTools() return emptyList(); } - AnnotationLayer layer = recommenderModel.getObject().getLayer(); - AnnotationFeature feature = recommenderModel.getObject().getFeature(); + var layer = recommenderModel.getObject().getLayer(); + var feature = recommenderModel.getObject().getFeature(); if (layer == null || feature == null) { return emptyList(); } @@ -451,7 +452,7 @@ private List> listTools() private void actionSave(AjaxRequestTarget aTarget) { - Recommender recommender = recommenderModel.getObject(); + var recommender = recommenderModel.getObject(); recommender.setProject(recommender.getLayer().getProject()); recommendationService.createOrUpdateRecommender(recommender); diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java index bb9f8cc2461..7cb39bb9214 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImpl.java @@ -63,6 +63,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.uima.UIMAException; +import org.apache.uima.cas.AnnotationBaseFS; import org.apache.uima.cas.CAS; import org.apache.uima.cas.text.AnnotationFS; import org.apache.uima.resource.ResourceInitializationException; @@ -392,6 +393,12 @@ public Recommender getRecommender(long aId) return entityManager.find(Recommender.class, aId); } + @Override + public Recommender getRecommender(AnnotationSuggestion aSuggestion) + { + return getRecommender(aSuggestion.getVID().getId()); + } + @Override @Transactional public boolean existsRecommender(Project aProject, String aName) @@ -1059,7 +1066,7 @@ public AnnotationFS correctSuggestion(String aSessionOwner, SourceDocument aDocu @Override @Transactional - public AnnotationFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument, + public AnnotationBaseFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner, CAS aCas, AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation) throws AnnotationException @@ -1071,8 +1078,8 @@ public AnnotationFS acceptSuggestion(String aSessionOwner, SourceDocument aDocum var rls = layerRecommendtionSupportRegistry.findGenericExtension(aSuggestion); if (rls.isPresent()) { - return (AnnotationFS) rls.get().acceptSuggestion(aSessionOwner, aDocument, aDataOwner, - aCas, adapter, feature, aSuggestion, aLocation, ACCEPTED); + return rls.get().acceptSuggestion(aSessionOwner, aDocument, aDataOwner, aCas, adapter, + feature, aSuggestion, aLocation, ACCEPTED); } return null; diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java index 663da6b8186..9a4da06ee85 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java @@ -146,24 +146,24 @@ else if (candidates.isEmpty() || aAdapter.getLayer().isAllowStacking()) { @Override public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner, - AnnotationSuggestion suggestion, LearningRecordChangeLocation aAction) + AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction) { - var spanSuggestion = (SpanSuggestion) suggestion; + var suggestion = (SpanSuggestion) aSuggestion; // Hide the suggestion. This is faster than having to recalculate the visibility status // for the entire document or even for the part visible on screen. - spanSuggestion.hide(FLAG_TRANSIENT_REJECTED); + suggestion.hide(FLAG_TRANSIENT_REJECTED); - var recommender = recommendationService.getRecommender(spanSuggestion.getVID().getId()); + var recommender = recommendationService.getRecommender(suggestion); var feature = recommender.getFeature(); // Log the action to the learning record - learningRecordService.logRecord(aSessionOwner, aDocument, aDataOwner, spanSuggestion, - feature, REJECTED, aAction); + learningRecordService.logRecord(aSessionOwner, aDocument, aDataOwner, suggestion, feature, + REJECTED, aAction); // Send an application event that the suggestion has been rejected applicationEventPublisher.publishEvent(new RecommendationRejectedEvent(this, aDocument, - aDataOwner, spanSuggestion.getBegin(), spanSuggestion.getEnd(), - spanSuggestion.getCoveredText(), feature, spanSuggestion.getLabel())); + aDataOwner, suggestion.getBegin(), suggestion.getEnd(), suggestion.getCoveredText(), + feature, suggestion.getLabel())); } @@ -176,7 +176,7 @@ public void skipSuggestion(String aSessionOwner, SourceDocument aDocument, Strin // for the entire document or even for the part visible on screen. aSuggestion.hide(FLAG_SKIPPED); - var recommender = recommendationService.getRecommender(aSuggestion.getVID().getId()); + var recommender = recommendationService.getRecommender(aSuggestion); var feature = recommender.getFeature(); // Log the action to the learning record