diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/config/DocumentMetadataLayerSupportAutoConfiguration.java b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/config/DocumentMetadataLayerSupportAutoConfiguration.java index 0030d3e3d09..a540ea675a0 100644 --- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/config/DocumentMetadataLayerSupportAutoConfiguration.java +++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/config/DocumentMetadataLayerSupportAutoConfiguration.java @@ -33,8 +33,8 @@ import de.tudarmstadt.ukp.inception.ui.core.docanno.event.DocumentMetadataAnnotationActionUndoSupport; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSingletonCreatingWatcher; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSupport; -import de.tudarmstadt.ukp.inception.ui.core.docanno.sidebar.DocumentMetadataRecommendationSupport; import de.tudarmstadt.ukp.inception.ui.core.docanno.sidebar.DocumentMetadataSidebarFactory; +import de.tudarmstadt.ukp.inception.ui.core.docanno.sidebar.MetadataSuggestionSupport; /** * Provides support for document-level annotations. @@ -85,12 +85,12 @@ public DocumentMetadataAnnotationActionUndoSupport documentMetadataAnnotationAct @Bean @ConditionalOnProperty(prefix = "documentmetadata", name = "enabled", havingValue = "true", matchIfMissing = true) - public DocumentMetadataRecommendationSupport documentMetadataRecommendationSupport( + public MetadataSuggestionSupport metadataSuggestionSupport( RecommendationService aRecommendationService, LearningRecordService aLearningRecordService, ApplicationEventPublisher aApplicationEventPublisher) { - return new DocumentMetadataRecommendationSupport(aRecommendationService, - aLearningRecordService, aApplicationEventPublisher); + return new MetadataSuggestionSupport(aRecommendationService, aLearningRecordService, + aApplicationEventPublisher); } } 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 80e23e446a6..d27fde64378 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 @@ -195,7 +195,7 @@ private void actionAccept(AjaxRequestTarget aTarget, AnnotationListItem aItem) var aCas = jcasProvider.get(); - var annotation = new DocumentMetadataRecommendationSupport(recommendationService, + var annotation = new MetadataSuggestionSupport(recommendationService, learningRecordService, applicationEventPublisherHolder.get()).acceptSuggestion( sessionOwner.getUsername(), state.getObject().getDocument(), dataOwner, aCas, adapter, feature, suggestion, MAIN_EDITOR, ACCEPTED); diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataRecommendationSupport.java b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java similarity index 94% rename from inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataRecommendationSupport.java rename to inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java index 3c9992842ec..597f3de9aff 100644 --- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/DocumentMetadataRecommendationSupport.java +++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/sidebar/MetadataSuggestionSupport.java @@ -28,7 +28,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendationSupport_ImplBase; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupport_ImplBase; import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; @@ -41,11 +41,11 @@ import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerAdapter; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerTraits; -public class DocumentMetadataRecommendationSupport - extends LayerRecommendationSupport_ImplBase +public class MetadataSuggestionSupport + extends SuggestionSupport_ImplBase { - public DocumentMetadataRecommendationSupport(RecommendationService aRecommendationService, + public MetadataSuggestionSupport(RecommendationService aRecommendationService, LearningRecordService aLearningRecordService, ApplicationEventPublisher aApplicationEventPublisher) { diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommenderTypeSystemUtils.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommenderTypeSystemUtils.java index 4bc334f624b..1cd8a92d23d 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommenderTypeSystemUtils.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/RecommenderTypeSystemUtils.java @@ -21,6 +21,7 @@ import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_SCORE_EXPLANATION_SUFFIX; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_SCORE_SUFFIX; +import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.apache.uima.cas.CAS.TYPE_NAME_BOOLEAN; import static org.apache.uima.cas.CAS.TYPE_NAME_DOUBLE; @@ -29,17 +30,34 @@ import java.lang.invoke.MethodHandles; import java.util.List; +import org.apache.uima.cas.CAS; +import org.apache.uima.fit.factory.CasFactory; +import org.apache.uima.resource.ResourceInitializationException; import org.apache.uima.resource.metadata.TypeSystemDescription; +import org.apache.uima.util.TypeSystemUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.inception.support.WebAnnoConst; +import de.tudarmstadt.ukp.inception.support.uima.SegmentationUtils; public class RecommenderTypeSystemUtils { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static CAS makePredictionCas(CAS aOriginalCas, AnnotationFeature... aFeatures) + throws ResourceInitializationException + { + var tsd = TypeSystemUtil.typeSystem2TypeSystemDescription(aOriginalCas.getTypeSystem()); + RecommenderTypeSystemUtils.addPredictionFeaturesToTypeSystem(tsd, asList(aFeatures)); + var predictionCas = CasFactory.createCas(tsd); + predictionCas.setDocumentText(aOriginalCas.getDocumentText()); + SegmentationUtils.splitSentences(predictionCas); + SegmentationUtils.tokenize(predictionCas); + return predictionCas; + } + public static void addPredictionFeaturesToTypeSystem(TypeSystemDescription tsd, List features) { diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport.java similarity index 97% rename from inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport.java rename to inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport.java index 13d0d35ffb0..0509ac26e69 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport.java @@ -33,7 +33,7 @@ import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; import de.tudarmstadt.ukp.inception.support.extensionpoint.Extension; -public interface LayerRecommendationSupport +public interface SuggestionSupport extends Extension { AnnotationBaseFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument, diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendtionSupportRegistry.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupportRegistry.java similarity index 87% rename from inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendtionSupportRegistry.java rename to inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupportRegistry.java index 875632d992f..ecb85797fca 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendtionSupportRegistry.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupportRegistry.java @@ -20,8 +20,8 @@ import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; import de.tudarmstadt.ukp.inception.support.extensionpoint.ContextLookupExtensionPoint; -public interface LayerRecommendtionSupportRegistry - extends ContextLookupExtensionPoint> +public interface SuggestionSupportRegistry + extends ContextLookupExtensionPoint> { } diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport_ImplBase.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java similarity index 94% rename from inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport_ImplBase.java rename to inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java index 87dd7ae7a44..5d3f126c9b5 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/LayerRecommendationSupport_ImplBase.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java @@ -36,8 +36,8 @@ import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; import de.tudarmstadt.ukp.inception.support.uima.ICasUtil; -public abstract class LayerRecommendationSupport_ImplBase - implements LayerRecommendationSupport, BeanNameAware +public abstract class SuggestionSupport_ImplBase + implements SuggestionSupport, BeanNameAware { protected final RecommendationService recommendationService; protected final LearningRecordService learningRecordService; @@ -45,7 +45,7 @@ public abstract class LayerRecommendationSupport_ImplBase> aExtensions) + public SuggestionSupportRegistry layerRecommendtionSupportRegistry( + @Lazy @Autowired(required = false) List> aExtensions) { return new LayerRecommendtionSupportRegistryImpl(aExtensions); } diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/LayerRecommendtionSupportRegistryImpl.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/LayerRecommendtionSupportRegistryImpl.java index 5c2e222570c..2c9ccd035d8 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/LayerRecommendtionSupportRegistryImpl.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/LayerRecommendtionSupportRegistryImpl.java @@ -23,25 +23,25 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendationSupport; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendtionSupportRegistry; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupport; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupportRegistry; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; import de.tudarmstadt.ukp.inception.support.extensionpoint.ExtensionPoint_ImplBase; public class LayerRecommendtionSupportRegistryImpl - extends ExtensionPoint_ImplBase> - implements LayerRecommendtionSupportRegistry + extends ExtensionPoint_ImplBase> + implements SuggestionSupportRegistry { @Autowired public LayerRecommendtionSupportRegistryImpl( - @Lazy @Autowired(required = false) List> aExtensions) + @Lazy @Autowired(required = false) List> aExtensions) { super(aExtensions); } @SuppressWarnings("unchecked") @Override - public > Optional findGenericExtension( + public > Optional findGenericExtension( AnnotationSuggestion aKey) { return getExtensions().stream() // 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 0fa301d1489..5d78087469c 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 @@ -109,7 +109,7 @@ import de.tudarmstadt.ukp.inception.project.api.ProjectService; import de.tudarmstadt.ukp.inception.project.api.event.AfterProjectRemovedEvent; import de.tudarmstadt.ukp.inception.project.api.event.BeforeProjectRemovedEvent; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendtionSupportRegistry; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupportRegistry; import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommenderFactoryRegistry; @@ -180,7 +180,7 @@ public class RecommendationServiceImpl private final ProjectService projectService; private final ApplicationEventPublisher applicationEventPublisher; private final PreferencesService preferencesService; - private final LayerRecommendtionSupportRegistry layerRecommendtionSupportRegistry; + private final SuggestionSupportRegistry layerRecommendtionSupportRegistry; private final ConcurrentMap trainingTaskCounter; private final ConcurrentMap states; @@ -210,7 +210,7 @@ public RecommendationServiceImpl(PreferencesService aPreferencesService, SchedulingService aSchedulingService, AnnotationSchemaService aAnnoService, DocumentService aDocumentService, ProjectService aProjectService, EntityManager aEntityManager, ApplicationEventPublisher aApplicationEventPublisher, - LayerRecommendtionSupportRegistry aLayerRecommendtionSupportRegistry) + SuggestionSupportRegistry aLayerRecommendtionSupportRegistry) { preferencesService = aPreferencesService; sessionRegistry = aSessionRegistry; @@ -233,7 +233,7 @@ public RecommendationServiceImpl(PreferencesService aPreferencesService, RecommenderFactoryRegistry aRecommenderFactoryRegistry, SchedulingService aSchedulingService, AnnotationSchemaService aAnnoService, DocumentService aDocumentService, - LayerRecommendtionSupportRegistry aLayerRecommendtionSupportRegistry, + SuggestionSupportRegistry aLayerRecommendtionSupportRegistry, EntityManager aEntityManager) { this(aPreferencesService, aSessionRegistry, aUserRepository, aRecommenderFactoryRegistry, diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationRecommendationSupport.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionSupport.java similarity index 98% rename from inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationRecommendationSupport.java rename to inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionSupport.java index dc207f94ce1..13ac0e229b6 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationRecommendationSupport.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionSupport.java @@ -47,7 +47,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.relation.RelationAdapter; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendationSupport_ImplBase; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupport_ImplBase; import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; @@ -62,14 +62,14 @@ import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; -public class RelationRecommendationSupport - extends LayerRecommendationSupport_ImplBase +public class RelationSuggestionSupport + extends SuggestionSupport_ImplBase { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final AnnotationSchemaService schemaService; - public RelationRecommendationSupport(RecommendationService aRecommendationService, + public RelationSuggestionSupport(RecommendationService aRecommendationService, LearningRecordService aLearningRecordService, ApplicationEventPublisher aApplicationEventPublisher, AnnotationSchemaService aSchemaService) diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanRecommendationSupport.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java similarity index 98% rename from inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanRecommendationSupport.java rename to inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java index b0e19d60808..5caecca202b 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanRecommendationSupport.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionSupport.java @@ -54,7 +54,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanAdapter; -import de.tudarmstadt.ukp.inception.recommendation.api.LayerRecommendationSupport_ImplBase; +import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionSupport_ImplBase; import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.event.RecommendationRejectedEvent; @@ -70,14 +70,14 @@ import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; -public class SpanRecommendationSupport - extends LayerRecommendationSupport_ImplBase +public class SpanSuggestionSupport + extends SuggestionSupport_ImplBase { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final AnnotationSchemaService schemaService; - public SpanRecommendationSupport(RecommendationService aRecommendationService, + public SpanSuggestionSupport(RecommendationService aRecommendationService, LearningRecordService aLearningRecordService, ApplicationEventPublisher aApplicationEventPublisher, AnnotationSchemaService aSchemaService) diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/Fixtures.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/Fixtures.java index fa84dfe8ab4..4e7d92aaf77 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/Fixtures.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/Fixtures.java @@ -25,6 +25,7 @@ import java.util.List; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; +import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.RelationSuggestion; @@ -85,4 +86,24 @@ static SuggestionDocumentGroup makeRelationSuggestionGroup( return new SuggestionDocumentGroup<>(suggestions); } + + public static SpanSuggestion makeSuggestion(int aBegin, int aEnd, String aLabel, + SourceDocument aDoc, AnnotationLayer aLayer, AnnotationFeature aFeature) + { + return new SpanSuggestion(0, // aId, + 0, // aRecommenderId, + "", // aRecommenderName + aLayer.getId(), // aLayerId, + aFeature.getName(), // aFeature, + aDoc.getName(), // aDocumentName + aBegin, // aBegin + aEnd, // aEnd + "", // aCoveredText, + aLabel, // aLabel + aLabel, // aUiLabel + 0.0, // aScore + "", // aScoreExplanation, + NEVER // autoAccept + ); + } } diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtractionTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/MetadataSuggestionExtractionTest.java similarity index 64% rename from inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtractionTest.java rename to inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/MetadataSuggestionExtractionTest.java index 0910f991c3e..be08bd861fe 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtractionTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/MetadataSuggestionExtractionTest.java @@ -18,16 +18,13 @@ package de.tudarmstadt.ukp.inception.recommendation.service; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; -import static de.tudarmstadt.ukp.inception.support.uima.AnnotationBuilder.buildAnnotation; import static de.tudarmstadt.ukp.inception.support.uima.FeatureStructureBuilder.buildFS; -import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import org.apache.uima.cas.CAS; import org.apache.uima.fit.factory.CasFactory; import org.apache.uima.fit.factory.TypeSystemDescriptionFactory; -import org.apache.uima.resource.ResourceInitializationException; import org.apache.uima.resource.metadata.FeatureDescription; import org.apache.uima.resource.metadata.TypeDescription; import org.apache.uima.resource.metadata.TypeSystemDescription; @@ -38,20 +35,16 @@ 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.dkpro.core.api.ner.type.NamedEntity; -import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; import de.tudarmstadt.ukp.inception.recommendation.api.RecommenderTypeSystemUtils; import de.tudarmstadt.ukp.inception.recommendation.api.model.MetadataSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender; -import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion; import de.tudarmstadt.ukp.inception.support.uima.SegmentationUtils; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSupport; -class SuggestionExtractionTest +class MetadataSuggestionExtractionTest { private Project project; private SourceDocument document; - private String text; private TypeSystemDescription tsd; private CAS originalCas; private TypeDescription metadataType; @@ -70,71 +63,18 @@ void setup() throws Exception .withName("Doc") // .build(); - text = "This is a test."; - tsd = TypeSystemDescriptionFactory.createTypeSystemDescription(); metadataType = tsd.addType("custom.Metadata", "", CAS.TYPE_NAME_ANNOTATION_BASE); metadataLabelFeature = metadataType.addFeature("value", "", CAS.TYPE_NAME_STRING); originalCas = CasFactory.createCas(tsd); - originalCas.setDocumentText(text); + originalCas.setDocumentText("This is a test."); SegmentationUtils.splitSentences(originalCas); SegmentationUtils.tokenize(originalCas); } - @Test - void testSpanExtraction() throws Exception - { - var layer = AnnotationLayer.builder() // - .withId(1l) // - .forJCasClass(NamedEntity.class) // - .withType(SpanLayerSupport.TYPE) // - .build(); - var feature = AnnotationFeature.builder() // - .withLayer(layer) // - .withName(NamedEntity._FeatName_value) // - .build(); - var recommender = Recommender.builder() // - .withId(1l) // - .withName("recommender") // - .withProject(project) // - .withLayer(layer) // - .withFeature(feature) // - .build(); - - var predictionCas = makePredictionCas(feature); - - buildAnnotation(predictionCas, feature.getLayer().getName()) // - .on("\\bis\\b") // - .withFeature(feature.getName(), "verb") // - .withFeature(FEATURE_NAME_IS_PREDICTION, true) // - .buildAndAddToIndexes(); - - var suggestions = SuggestionExtraction.extractSuggestions(1, originalCas, predictionCas, - document, recommender); - - assertThat(suggestions) // - .filteredOn(a -> a instanceof SpanSuggestion) // - .map(a -> (SpanSuggestion) a) // - .extracting( // - SpanSuggestion::getRecommenderName, // - SpanSuggestion::getLabel) // - .containsExactly( // - tuple(recommender.getName(), "verb")); - } - - private CAS makePredictionCas(AnnotationFeature feature) throws ResourceInitializationException - { - RecommenderTypeSystemUtils.addPredictionFeaturesToTypeSystem(tsd, asList(feature)); - var predictionCas = CasFactory.createCas(tsd); - predictionCas.setDocumentText(text); - SegmentationUtils.splitSentences(predictionCas); - SegmentationUtils.tokenize(predictionCas); - return predictionCas; - } - @Test void testDocumentMetadataExtraction() throws Exception { @@ -154,8 +94,9 @@ void testDocumentMetadataExtraction() throws Exception .withLayer(layer) // .withFeature(feature) // .build(); + AnnotationFeature[] aFeatures = { feature }; - var predictionCas = makePredictionCas(feature); + var predictionCas = RecommenderTypeSystemUtils.makePredictionCas(originalCas, aFeatures); buildFS(predictionCas, feature.getLayer().getName()) // .withFeature(feature.getName(), "happy") // diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplIntegrationTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplIntegrationTest.java index 59697724b10..0d7584a8315 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplIntegrationTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplIntegrationTest.java @@ -119,7 +119,7 @@ public class RecommendationServiceImplIntegrationTest public void setUp() throws Exception { layerRecommendtionSupportRegistry = new LayerRecommendtionSupportRegistryImpl( - asList(new SpanRecommendationSupport(sut, sut, null, schemaService))); + asList(new SpanSuggestionSupport(sut, sut, null, schemaService))); layerRecommendtionSupportRegistry.init(); sut = new RecommendationServiceImpl(null, null, null, recommenderFactoryRegistry, null, diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplTest.java index a595ea9e1e5..f5b1e964ffc 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RecommendationServiceImplTest.java @@ -25,10 +25,6 @@ import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_SCORE_EXPLANATION_SUFFIX; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_SCORE_SUFFIX; -import static de.tudarmstadt.ukp.inception.recommendation.api.model.AutoAcceptMode.NEVER; -import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.REJECTED; -import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.SKIPPED; -import static de.tudarmstadt.ukp.inception.recommendation.service.SpanRecommendationSupport.hideSuggestionsRejectedOrSkipped; import static de.tudarmstadt.ukp.inception.recommendation.service.SuggestionExtraction.extractSuggestions; import static de.tudarmstadt.ukp.inception.recommendation.service.SuggestionExtraction.getOffsets; import static de.tudarmstadt.ukp.inception.support.uima.FeatureStructureBuilder.buildFS; @@ -62,7 +58,6 @@ import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Token; import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; 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.Offset; import de.tudarmstadt.ukp.inception.recommendation.api.model.Predictions; import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender; @@ -147,92 +142,6 @@ void testReconciliation() throws Exception .containsExactlyInAnyOrder(tuple(0, "aged", 1), tuple(3, "added", 0)); } - @Test - void thatRejectedSuggestionIsHidden() - { - var records = asList(LearningRecord.builder() // - .withSourceDocument(doc1) // - .withLayer(layer1) // - .withAnnotationFeature(feature1) // - .withOffsetBegin(0) // - .withOffsetEnd(10) // - .withAnnotation("x") // - .withUserAction(REJECTED) // - .build()); - - var doc1Suggestion = makeSuggestion(0, 10, "x", doc1, layer1, feature1); - assertThat(doc1Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc1Suggestion, records); - assertThat(doc1Suggestion.isVisible()) // - .as("Suggestion in same document/layer/feature should be hidden") // - .isFalse(); - assertThat(doc1Suggestion.getReasonForHiding().trim()).isEqualTo("rejected"); - - var doc2Suggestion = makeSuggestion(0, 10, "x", doc2, layer1, feature1); - assertThat(doc2Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc2Suggestion, records); - assertThat(doc2Suggestion.isVisible()) // - .as("Suggestion in other document should not be hidden") // - .isTrue(); - - var doc3Suggestion = makeSuggestion(0, 10, "x", doc1, layer2, feature1); - assertThat(doc3Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); - assertThat(doc3Suggestion.isVisible()) // - .as("Suggestion in other layer should not be hidden") // - .isTrue(); - - var doc4Suggestion = makeSuggestion(0, 10, "x", doc1, layer1, feature2); - assertThat(doc4Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); - assertThat(doc4Suggestion.isVisible()) // - .as("Suggestion in other feature should not be hidden") // - .isTrue(); - } - - @Test - void thatSkippedSuggestionIsHidden() - { - var records = asList(LearningRecord.builder() // - .withSourceDocument(doc1) // - .withLayer(layer1) // - .withAnnotationFeature(feature1) // - .withOffsetBegin(0) // - .withOffsetEnd(10) // - .withAnnotation("x") // - .withUserAction(SKIPPED) // - .build()); - - var doc1Suggestion = makeSuggestion(0, 10, "x", doc1, layer1, feature1); - assertThat(doc1Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc1Suggestion, records); - assertThat(doc1Suggestion.isVisible()) // - .as("Suggestion in same document/layer/feature should be hidden") // - .isFalse(); - assertThat(doc1Suggestion.getReasonForHiding().trim()).isEqualTo("skipped"); - - var doc2Suggestion = makeSuggestion(0, 10, "x", doc2, layer1, feature1); - assertThat(doc2Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc2Suggestion, records); - assertThat(doc2Suggestion.isVisible()) // - .as("Suggestion in other document should not be hidden") // - .isTrue(); - - var doc3Suggestion = makeSuggestion(0, 10, "x", doc1, layer2, feature1); - assertThat(doc3Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); - assertThat(doc3Suggestion.isVisible()) // - .as("Suggestion in other layer should not be hidden") // - .isTrue(); - - var doc4Suggestion = makeSuggestion(0, 10, "x", doc1, layer1, feature2); - assertThat(doc4Suggestion.isVisible()).isTrue(); - hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); - assertThat(doc4Suggestion.isVisible()) // - .as("Suggestion in other feature should not be hidden") // - .isTrue(); - } - @Test void testOffsetAlignmentWithAnchoringOnCharacters() throws Exception { @@ -398,23 +307,4 @@ void testExtractSuggestionsWithSpanSuggestions() throws Exception tuple("bar", 0.5d, "two", new Offset(5, 9))); } - private SpanSuggestion makeSuggestion(int aBegin, int aEnd, String aLabel, SourceDocument aDoc, - AnnotationLayer aLayer, AnnotationFeature aFeature) - { - return new SpanSuggestion(0, // aId, - 0, // aRecommenderId, - "", // aRecommenderName - aLayer.getId(), // aLayerId, - aFeature.getName(), // aFeature, - aDoc.getName(), // aDocumentName - aBegin, // aBegin - aEnd, // aEnd - "", // aCoveredText, - aLabel, // aLabel - aLabel, // aUiLabel - 0.0, // aScore - "", // aScoreExplanation, - NEVER // autoAccept - ); - } } diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionVisibilityCalculationTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionVisibilityCalculationTest.java index b4a554bb5a7..4e104edcf98 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionVisibilityCalculationTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/RelationSuggestionVisibilityCalculationTest.java @@ -20,6 +20,7 @@ import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.getInvisibleSuggestions; import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.getVisibleSuggestions; import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.makeRelationSuggestionGroup; +import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.apache.uima.cas.CAS.TYPE_NAME_STRING; import static org.assertj.core.api.Assertions.assertThat; @@ -27,11 +28,9 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.List; import org.apache.uima.cas.CAS; import org.apache.uima.fit.factory.JCasFactory; -import org.apache.uima.jcas.JCas; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -61,29 +60,23 @@ public class RelationSuggestionVisibilityCalculationTest private AnnotationLayer layer; private AnnotationFeature feature; - private RelationRecommendationSupport sut; + private RelationSuggestionSupport sut; @BeforeEach public void setUp() throws Exception { - layer = new AnnotationLayer(); - layer.setName(Dependency._TypeName); - layer.setId(42l); + layer = AnnotationLayer.builder().withId(42l).forJCasClass(Dependency.class).build(); feature = AnnotationFeature.builder().withId(2l).withLayer(layer) - .withName(Dependency._FeatName_DependencyType).build(); + .withName(Dependency._FeatName_DependencyType).withType(TYPE_NAME_STRING).build(); - project = new Project(); - project.setName("Test Project"); + project = Project.builder().withName("Test Project").build(); doc = SourceDocument.builder().withId(12l).withName("doc").withProject(project).build(); - List featureList = new ArrayList(); - featureList - .add(new AnnotationFeature(Dependency._FeatName_DependencyType, TYPE_NAME_STRING)); - when(annoService.listSupportedFeatures(layer)).thenReturn(featureList); + when(annoService.listSupportedFeatures(layer)).thenReturn(asList(feature)); - sut = new RelationRecommendationSupport(null, learningRecordService, null, annoService); + sut = new RelationSuggestionSupport(null, learningRecordService, null, annoService); } @Test @@ -144,18 +137,17 @@ public void thatVisibilityIsRestoredWhenOverlappingAnnotationIsRemoved() throws private CAS getTestCas() throws Exception { - String documentText = "Dies ist ein Testtext, ach ist der schoen, der schoenste von allen" - + " Testtexten."; - JCas jcas = JCasFactory.createText(documentText, "de"); + var jcas = JCasFactory.createText("Dies ist ein Testtext, ach ist der schoen, " + + "der schoenste von allen Testtexten.", "de"); - Token governor = new Token(jcas, 0, 3); + var governor = new Token(jcas, 0, 3); governor.addToIndexes(); // the annotation's feature value is initialized as null - Token dependent = new Token(jcas, 13, 20); + var dependent = new Token(jcas, 13, 20); dependent.addToIndexes(); - Dependency dep = new Dependency(jcas, dependent.getBegin(), dependent.getEnd()); + var dep = new Dependency(jcas, dependent.getBegin(), dependent.getEnd()); dep.setDependent(dependent); dep.setGovernor(governor); dep.setDependencyType("DEP"); diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionExtractionTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionExtractionTest.java new file mode 100644 index 00000000000..d61e7aee8db --- /dev/null +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionExtractionTest.java @@ -0,0 +1,108 @@ +/* + * 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.service; + +import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; +import static de.tudarmstadt.ukp.inception.support.uima.AnnotationBuilder.buildAnnotation; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +import org.apache.uima.cas.CAS; +import org.apache.uima.fit.factory.CasFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +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.dkpro.core.api.ner.type.NamedEntity; +import de.tudarmstadt.ukp.inception.annotation.layer.span.SpanLayerSupport; +import de.tudarmstadt.ukp.inception.recommendation.api.RecommenderTypeSystemUtils; +import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender; +import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion; +import de.tudarmstadt.ukp.inception.support.uima.SegmentationUtils; + +class SpanSuggestionExtractionTest +{ + private Project project; + private SourceDocument document; + private CAS originalCas; + + @BeforeEach + void setup() throws Exception + { + project = Project.builder() // + .withId(1l) // + .withName("Test") // + .build(); + document = SourceDocument.builder() // + .withId(1l) // + .withProject(project) // + .withName("Doc") // + .build(); + + originalCas = CasFactory.createCas(); + originalCas.setDocumentText("This is a test."); + + SegmentationUtils.splitSentences(originalCas); + SegmentationUtils.tokenize(originalCas); + } + + @Test + void testSpanExtraction() throws Exception + { + var layer = AnnotationLayer.builder() // + .withId(1l) // + .forJCasClass(NamedEntity.class) // + .withType(SpanLayerSupport.TYPE) // + .build(); + var feature = AnnotationFeature.builder() // + .withLayer(layer) // + .withName(NamedEntity._FeatName_value) // + .build(); + var recommender = Recommender.builder() // + .withId(1l) // + .withName("recommender") // + .withProject(project) // + .withLayer(layer) // + .withFeature(feature) // + .build(); + AnnotationFeature[] aFeatures = { feature }; + + var predictionCas = RecommenderTypeSystemUtils.makePredictionCas(originalCas, aFeatures); + + buildAnnotation(predictionCas, feature.getLayer().getName()) // + .on("\\bis\\b") // + .withFeature(feature.getName(), "verb") // + .withFeature(FEATURE_NAME_IS_PREDICTION, true) // + .buildAndAddToIndexes(); + + var suggestions = SuggestionExtraction.extractSuggestions(1, originalCas, predictionCas, + document, recommender); + + assertThat(suggestions) // + .filteredOn(a -> a instanceof SpanSuggestion) // + .map(a -> (SpanSuggestion) a) // + .extracting( // + SpanSuggestion::getRecommenderName, // + SpanSuggestion::getLabel) // + .containsExactly( // + tuple(recommender.getName(), "verb")); + } +} diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionVisibilityCalculationTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionVisibilityCalculationTest.java index 695528c8e1f..0bfb80cddcb 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionVisibilityCalculationTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/service/SpanSuggestionVisibilityCalculationTest.java @@ -17,15 +17,19 @@ */ package de.tudarmstadt.ukp.inception.recommendation.service; +import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.REJECTED; +import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.SKIPPED; import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.getInvisibleSuggestions; import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.getVisibleSuggestions; import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.makeSpanSuggestionGroup; +import static de.tudarmstadt.ukp.inception.recommendation.service.Fixtures.makeSuggestion; +import static de.tudarmstadt.ukp.inception.recommendation.service.SpanSuggestionSupport.hideSuggestionsRejectedOrSkipped; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.apache.uima.cas.CAS.TYPE_NAME_STRING; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.lenient; import java.util.ArrayList; import java.util.List; @@ -63,31 +67,34 @@ public class SpanSuggestionVisibilityCalculationTest private Project project; private SourceDocument doc; + private SourceDocument doc2; private AnnotationLayer layer; + private AnnotationLayer layer2; private AnnotationFeature feature; + private AnnotationFeature feature2; - private SpanRecommendationSupport sut; + private SpanSuggestionSupport sut; @BeforeEach public void setUp() throws Exception { - layer = new AnnotationLayer(); - layer.setName(NamedEntity._TypeName); - layer.setId(42l); + layer = AnnotationLayer.builder().withId(42l).forJCasClass(NamedEntity.class).build(); + layer2 = AnnotationLayer.builder().withId(43l).withName("custom.Layer2").build(); feature = AnnotationFeature.builder().withId(2l).withLayer(layer) - .withName(NamedEntity._FeatName_value).build(); + .withName(NamedEntity._FeatName_value).withType(TYPE_NAME_STRING).build(); + feature2 = AnnotationFeature.builder().withId(3l).withLayer(layer2).withName("value") + .withType(TYPE_NAME_STRING).build(); - project = new Project(); - project.setName("Test Project"); + project = Project.builder().withName("Test Project").build(); doc = SourceDocument.builder().withId(12l).withName("doc").withProject(project).build(); + doc2 = SourceDocument.builder().withId(13l).withName("doc2").withProject(project).build(); - List featureList = new ArrayList(); - featureList.add(new AnnotationFeature(NamedEntity._FeatName_value, TYPE_NAME_STRING)); - when(annoService.listSupportedFeatures(layer)).thenReturn(featureList); + lenient().when(annoService.listSupportedFeatures(layer)).thenReturn(asList(feature)); + lenient().when(annoService.listSupportedFeatures(layer2)).thenReturn(asList(feature2)); - sut = new SpanRecommendationSupport(null, learningRecordService, null, annoService); + sut = new SpanSuggestionSupport(null, learningRecordService, null, annoService); } @Test @@ -268,6 +275,92 @@ public void thatOverlappingSuggestionsAreNotHiddenWhenStackingIsEnabled() throws .containsExactly(suggestion1, suggestion2); } + @Test + void thatRejectedSuggestionIsHidden() + { + var records = asList(LearningRecord.builder() // + .withSourceDocument(doc) // + .withLayer(layer) // + .withAnnotationFeature(feature) // + .withOffsetBegin(0) // + .withOffsetEnd(10) // + .withAnnotation("x") // + .withUserAction(REJECTED) // + .build()); + + var docSuggestion = makeSuggestion(0, 10, "x", doc, layer, feature); + assertThat(docSuggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(docSuggestion, records); + assertThat(docSuggestion.isVisible()) // + .as("Suggestion in same document/layer/feature should be hidden") // + .isFalse(); + assertThat(docSuggestion.getReasonForHiding().trim()).isEqualTo("rejected"); + + var doc2Suggestion = makeSuggestion(0, 10, "x", doc2, layer, feature); + assertThat(doc2Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc2Suggestion, records); + assertThat(doc2Suggestion.isVisible()) // + .as("Suggestion in other document should not be hidden") // + .isTrue(); + + var doc3Suggestion = makeSuggestion(0, 10, "x", doc, layer2, feature); + assertThat(doc3Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); + assertThat(doc3Suggestion.isVisible()) // + .as("Suggestion in other layer should not be hidden") // + .isTrue(); + + var doc4Suggestion = makeSuggestion(0, 10, "x", doc, layer, feature2); + assertThat(doc4Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); + assertThat(doc4Suggestion.isVisible()) // + .as("Suggestion in other feature should not be hidden") // + .isTrue(); + } + + @Test + void thatSkippedSuggestionIsHidden() + { + var records = asList(LearningRecord.builder() // + .withSourceDocument(doc) // + .withLayer(layer) // + .withAnnotationFeature(feature) // + .withOffsetBegin(0) // + .withOffsetEnd(10) // + .withAnnotation("x") // + .withUserAction(SKIPPED) // + .build()); + + var docSuggestion = makeSuggestion(0, 10, "x", doc, layer, feature); + assertThat(docSuggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(docSuggestion, records); + assertThat(docSuggestion.isVisible()) // + .as("Suggestion in same document/layer/feature should be hidden") // + .isFalse(); + assertThat(docSuggestion.getReasonForHiding().trim()).isEqualTo("skipped"); + + var doc2Suggestion = makeSuggestion(0, 10, "x", doc2, layer, feature); + assertThat(doc2Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc2Suggestion, records); + assertThat(doc2Suggestion.isVisible()) // + .as("Suggestion in other document should not be hidden") // + .isTrue(); + + var doc3Suggestion = makeSuggestion(0, 10, "x", doc, layer2, feature); + assertThat(doc3Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); + assertThat(doc3Suggestion.isVisible()) // + .as("Suggestion in other layer should not be hidden") // + .isTrue(); + + var doc4Suggestion = makeSuggestion(0, 10, "x", doc, layer, feature2); + assertThat(doc4Suggestion.isVisible()).isTrue(); + hideSuggestionsRejectedOrSkipped(doc3Suggestion, records); + assertThat(doc4Suggestion.isVisible()) // + .as("Suggestion in other feature should not be hidden") // + .isTrue(); + } + private CAS getTestCas() throws Exception { var documentText = "Dies ist ein Testtext, ach ist der schoen, der schoenste von allen"