From a34fcffedafdaddef278eb348fa9e6d4fd22e7d6 Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Sun, 24 Dec 2023 20:29:53 +0100 Subject: [PATCH] #2696 - Document-level recommendations - Continue moving extraction logic into the suggestion supports --- .../sidebar/MetadataSuggestionSupport.java | 25 ++++++++ .../api/SuggestionSupport_ImplBase.java | 29 +++++++++ .../api/model/SuggestionDocumentGroup.java | 4 +- .../api/recommender}/ExtractionContext.java | 4 +- .../relation/RelationSuggestionSupport.java | 9 +-- .../service/SuggestionExtraction.java | 63 +------------------ .../span/SpanSuggestionSupport.java | 9 +-- ...onSuggestionVisibilityCalculationTest.java | 1 - ...anSuggestionVisibilityCalculationTest.java | 1 - 9 files changed, 67 insertions(+), 78 deletions(-) rename inception/{inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service => inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender}/ExtractionContext.java (98%) 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 a7a313fa2ca..c15e30476f9 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 @@ -33,6 +33,7 @@ import org.apache.uima.cas.CAS; import org.apache.uima.cas.Feature; import org.apache.uima.jcas.cas.AnnotationBase; +import org.apache.uima.jcas.cas.TOP; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; @@ -51,6 +52,7 @@ import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction; import de.tudarmstadt.ukp.inception.recommendation.api.model.MetadataSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionGroup; +import de.tudarmstadt.ukp.inception.recommendation.api.recommender.ExtractionContext; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.api.adapter.TypeAdapter; @@ -277,4 +279,27 @@ public Optional getRenderer() { return Optional.empty(); } + + public static void extractSuggestion(ExtractionContext ctx, TOP predictedFS) + { + var autoAcceptMode = getAutoAcceptMode(predictedFS, ctx.getModeFeature()); + var labels = getPredictedLabels(predictedFS, ctx.getLabelFeature(), ctx.isMultiLabels()); + var score = predictedFS.getDoubleValue(ctx.getScoreFeature()); + var scoreExplanation = predictedFS.getStringValue(ctx.getScoreExplanationFeature()); + + for (var label : labels) { + var suggestion = MetadataSuggestion.builder() // + .withId(MetadataSuggestion.NEW_ID) // + .withGeneration(ctx.getGeneration()) // + .withRecommender(ctx.getRecommender()) // + .withDocumentName(ctx.getDocument().getName()) // + .withLabel(label) // + .withUiLabel(label) // + .withScore(score) // + .withScoreExplanation(scoreExplanation) // + .withAutoAcceptMode(autoAcceptMode) // + .build(); + ctx.getResult().add(suggestion); + } + } } diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java index 03159fcc7d8..a352059588c 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/SuggestionSupport_ImplBase.java @@ -23,6 +23,9 @@ import org.apache.uima.cas.AnnotationBaseFS; import org.apache.uima.cas.CAS; +import org.apache.uima.cas.Feature; +import org.apache.uima.cas.FeatureStructure; +import org.apache.uima.fit.util.FSUtil; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationEventPublisher; @@ -30,6 +33,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.inception.recommendation.api.event.RecommendationAcceptedEvent; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; +import de.tudarmstadt.ukp.inception.recommendation.api.model.AutoAcceptMode; import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordChangeLocation; import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @@ -95,4 +99,29 @@ protected void commmitLabel(String aSessionOwner, SourceDocument aDocument, Stri annotation, aFeature, aSuggestion.getLabel())); } } + + private static final String AUTO_ACCEPT_ON_FIRST_ACCESS = "on-first-access"; + + public static AutoAcceptMode getAutoAcceptMode(FeatureStructure aFS, Feature aModeFeature) + { + var autoAcceptMode = AutoAcceptMode.NEVER; + var autoAcceptFeatureValue = aFS.getStringValue(aModeFeature); + if (autoAcceptFeatureValue != null) { + switch (autoAcceptFeatureValue) { + case AUTO_ACCEPT_ON_FIRST_ACCESS: + autoAcceptMode = AutoAcceptMode.ON_FIRST_ACCESS; + } + } + return autoAcceptMode; + } + + public static String[] getPredictedLabels(FeatureStructure predictedFS, + Feature predictedFeature, boolean isStringMultiValue) + { + if (isStringMultiValue) { + return FSUtil.getFeature(predictedFS, predictedFeature, String[].class); + } + + return new String[] { predictedFS.getFeatureValueAsString(predictedFeature) }; + } } diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/SuggestionDocumentGroup.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/SuggestionDocumentGroup.java index c79d7fc5ba0..91ae9110dde 100644 --- a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/SuggestionDocumentGroup.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/model/SuggestionDocumentGroup.java @@ -77,8 +77,8 @@ public static SuggestionDocumentGroup groups * the list to retrieve suggestions from * @return a SuggestionDocumentGroup where only suggestions of type V are added */ - public static Map, SuggestionDocumentGroup> groupByType( - List aSuggestions) + public static Map, SuggestionDocumentGroup> // + groupByType(List aSuggestions) { if (aSuggestions == null || aSuggestions.isEmpty()) { return Collections.emptyMap(); diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/ExtractionContext.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/ExtractionContext.java similarity index 98% rename from inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/ExtractionContext.java rename to inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/ExtractionContext.java index 8f8774585bf..58777e21480 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/ExtractionContext.java +++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/ExtractionContext.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.tudarmstadt.ukp.inception.recommendation.service; +package de.tudarmstadt.ukp.inception.recommendation.api.recommender; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_AUTO_ACCEPT_MODE_SUFFIX; import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.FEATURE_NAME_IS_PREDICTION; @@ -191,4 +191,4 @@ public List getResult() { return result; } -} \ No newline at end of file +} diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionSupport.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionSupport.java index 475555ffe33..98db34b99ee 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionSupport.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionSupport.java @@ -62,8 +62,7 @@ import de.tudarmstadt.ukp.inception.recommendation.api.model.RelationPosition; import de.tudarmstadt.ukp.inception.recommendation.api.model.RelationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionGroup; -import de.tudarmstadt.ukp.inception.recommendation.service.ExtractionContext; -import de.tudarmstadt.ukp.inception.recommendation.service.SuggestionExtraction; +import de.tudarmstadt.ukp.inception.recommendation.api.recommender.ExtractionContext; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationComparisonUtils; import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; @@ -380,10 +379,8 @@ public Optional getRenderer() public static void extractSuggestion(ExtractionContext ctx, TOP predictedFS) { - var autoAcceptMode = SuggestionExtraction.getAutoAcceptMode(predictedFS, - ctx.getModeFeature()); - var labels = SuggestionExtraction.getPredictedLabels(predictedFS, ctx.getLabelFeature(), - ctx.isMultiLabels()); + var autoAcceptMode = getAutoAcceptMode(predictedFS, ctx.getModeFeature()); + var labels = getPredictedLabels(predictedFS, ctx.getLabelFeature(), ctx.isMultiLabels()); var score = predictedFS.getDoubleValue(ctx.getScoreFeature()); var scoreExplanation = predictedFS.getStringValue(ctx.getScoreExplanationFeature()); diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtraction.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtraction.java index 2e189832c3f..e4b0914ef31 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtraction.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/service/SuggestionExtraction.java @@ -17,80 +17,23 @@ */ package de.tudarmstadt.ukp.inception.recommendation.service; -import java.lang.invoke.MethodHandles; import java.util.List; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.Feature; -import org.apache.uima.cas.FeatureStructure; -import org.apache.uima.fit.util.FSUtil; -import org.apache.uima.jcas.cas.TOP; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; 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.model.AnnotationSuggestion; -import de.tudarmstadt.ukp.inception.recommendation.api.model.AutoAcceptMode; -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.recommender.ExtractionContext; import de.tudarmstadt.ukp.inception.recommendation.relation.RelationSuggestionSupport; import de.tudarmstadt.ukp.inception.recommendation.span.SpanSuggestionSupport; import de.tudarmstadt.ukp.inception.ui.core.docanno.layer.DocumentMetadataLayerSupport; +import de.tudarmstadt.ukp.inception.ui.core.docanno.sidebar.MetadataSuggestionSupport; public class SuggestionExtraction { - private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private static final String AUTO_ACCEPT_ON_FIRST_ACCESS = "on-first-access"; - - public static AutoAcceptMode getAutoAcceptMode(FeatureStructure aFS, Feature aModeFeature) - { - var autoAcceptMode = AutoAcceptMode.NEVER; - var autoAcceptFeatureValue = aFS.getStringValue(aModeFeature); - if (autoAcceptFeatureValue != null) { - switch (autoAcceptFeatureValue) { - case AUTO_ACCEPT_ON_FIRST_ACCESS: - autoAcceptMode = AutoAcceptMode.ON_FIRST_ACCESS; - } - } - return autoAcceptMode; - } - - public static String[] getPredictedLabels(FeatureStructure predictedFS, - Feature predictedFeature, boolean isStringMultiValue) - { - if (isStringMultiValue) { - return FSUtil.getFeature(predictedFS, predictedFeature, String[].class); - } - - return new String[] { predictedFS.getFeatureValueAsString(predictedFeature) }; - } - - static void extractDocumentMetadataSuggestion(ExtractionContext ctx, TOP predictedFS) - { - var autoAcceptMode = getAutoAcceptMode(predictedFS, ctx.getModeFeature()); - var labels = getPredictedLabels(predictedFS, ctx.getLabelFeature(), ctx.isMultiLabels()); - var score = predictedFS.getDoubleValue(ctx.getScoreFeature()); - var scoreExplanation = predictedFS.getStringValue(ctx.getScoreExplanationFeature()); - - for (var label : labels) { - var suggestion = MetadataSuggestion.builder() // - .withId(MetadataSuggestion.NEW_ID) // - .withGeneration(ctx.getGeneration()) // - .withRecommender(ctx.getRecommender()) // - .withDocumentName(ctx.getDocument().getName()) // - .withLabel(label) // - .withUiLabel(label) // - .withScore(score) // - .withScoreExplanation(scoreExplanation) // - .withAutoAcceptMode(autoAcceptMode) // - .build(); - ctx.getResult().add(suggestion); - } - } - public static List extractSuggestions(int aGeneration, CAS aOriginalCas, CAS aPredictionCas, SourceDocument aDocument, Recommender aRecommender) { @@ -112,7 +55,7 @@ public static List extractSuggestions(int aGeneration, CAS break; } case DocumentMetadataLayerSupport.TYPE: { - extractDocumentMetadataSuggestion(ctx, predictedFS); + MetadataSuggestionSupport.extractSuggestion(ctx, predictedFS); break; } default: diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionSupport.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionSupport.java index 4983e4acf3b..f2c36486dd5 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionSupport.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionSupport.java @@ -76,9 +76,8 @@ import de.tudarmstadt.ukp.inception.recommendation.api.model.RelationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionGroup; +import de.tudarmstadt.ukp.inception.recommendation.api.recommender.ExtractionContext; import de.tudarmstadt.ukp.inception.recommendation.config.RecommenderProperties; -import de.tudarmstadt.ukp.inception.recommendation.service.ExtractionContext; -import de.tudarmstadt.ukp.inception.recommendation.service.SuggestionExtraction; import de.tudarmstadt.ukp.inception.recommendation.util.OverlapIterator; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.api.adapter.AnnotationException; @@ -463,10 +462,8 @@ public Optional getRenderer() public static void extractSuggestion(ExtractionContext ctx, TOP predictedFS) { - var autoAcceptMode = SuggestionExtraction.getAutoAcceptMode(predictedFS, - ctx.getModeFeature()); - var labels = SuggestionExtraction.getPredictedLabels(predictedFS, ctx.getLabelFeature(), - ctx.isMultiLabels()); + var autoAcceptMode = getAutoAcceptMode(predictedFS, ctx.getModeFeature()); + var labels = getPredictedLabels(predictedFS, ctx.getLabelFeature(), ctx.isMultiLabels()); var score = predictedFS.getDoubleValue(ctx.getScoreFeature()); var scoreExplanation = predictedFS.getStringValue(ctx.getScoreExplanationFeature()); diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionVisibilityCalculationTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionVisibilityCalculationTest.java index 103889e24d2..7738e321921 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionVisibilityCalculationTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/relation/RelationSuggestionVisibilityCalculationTest.java @@ -45,7 +45,6 @@ import de.tudarmstadt.ukp.dkpro.core.api.syntax.type.dependency.Dependency; import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; -import de.tudarmstadt.ukp.inception.recommendation.relation.RelationSuggestionSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @ExtendWith(MockitoExtension.class) diff --git a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionVisibilityCalculationTest.java b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionVisibilityCalculationTest.java index 674f0410f8b..3f8f367c3fe 100644 --- a/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionVisibilityCalculationTest.java +++ b/inception/inception-recommendation/src/test/java/de/tudarmstadt/ukp/inception/recommendation/span/SpanSuggestionVisibilityCalculationTest.java @@ -55,7 +55,6 @@ import de.tudarmstadt.ukp.inception.recommendation.api.model.Offset; import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionDocumentGroup; -import de.tudarmstadt.ukp.inception.recommendation.span.SpanSuggestionSupport; import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService; @ExtendWith(MockitoExtension.class)