Skip to content

Commit

Permalink
#2696 - Document-level recommendations
Browse files Browse the repository at this point in the history
- Pull code to reject and skip suggestions up into the base class so that metadata and relation suggestion supports automatically get them
  • Loading branch information
reckart committed Dec 26, 2023
1 parent 3910642 commit bf47a1f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

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.ArrayList;
Expand All @@ -29,7 +27,6 @@
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.NotImplementedException;
import org.apache.uima.cas.AnnotationBaseFS;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.Feature;
Expand All @@ -45,7 +42,6 @@
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionRenderer;
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;
Expand Down Expand Up @@ -135,37 +131,6 @@ else if (candidates.isEmpty() || !aAdapter.getTraits(DocumentMetadataLayerTraits
return annotation;
}

@Override
public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction)
throws AnnotationException
{
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
var record = toLearningRecord(aDocument, aDataOwner, aSuggestion, feature, REJECTED,
aAction);
learningRecordService.logRecord(aSessionOwner, aDocument, record);

// Send an application event that the suggestion has been rejected
applicationEventPublisher.publishEvent(new RecommendationRejectedEvent(this, aDocument,
aDataOwner, feature, suggestion.getLabel()));
}

@Override
public void skipSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction)
throws AnnotationException
{
throw new NotImplementedException("Not yet implemented");
}

@Override
public <T extends AnnotationSuggestion> void calculateSuggestionVisibility(String aSessionOwner,
SourceDocument aDocument, CAS aCas, String aDataOwner, AnnotationLayer aLayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ AnnotationBaseFS acceptSuggestion(String aSessionOwner, SourceDocument aDocument
* if there was a problem rejecting the annotation.
*/
void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction)
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation)
throws AnnotationException;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
*/
package de.tudarmstadt.ukp.inception.recommendation.api;

import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_SKIPPED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_TRANSIENT_ACCEPTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_TRANSIENT_CORRECTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_TRANSIENT_REJECTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.ACCEPTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.REJECTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.SKIPPED;

import org.apache.uima.cas.AnnotationBaseFS;
import org.apache.uima.cas.CAS;
Expand All @@ -32,10 +36,12 @@
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature;
import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
import de.tudarmstadt.ukp.inception.recommendation.api.event.RecommendationAcceptedEvent;
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.AutoAcceptMode;
import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordChangeLocation;
import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction;
import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion;
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;
Expand Down Expand Up @@ -125,4 +131,46 @@ public static String[] getPredictedLabels(FeatureStructure predictedFS,

return new String[] { predictedFS.getFeatureValueAsString(predictedFeature) };
}

@Override
public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation)
throws AnnotationException
{
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.
suggestion.hide(FLAG_TRANSIENT_REJECTED);

var recommender = recommendationService.getRecommender(suggestion);
var feature = recommender.getFeature();
// Log the action to the learning record
var record = toLearningRecord(aDocument, aDataOwner, aSuggestion, feature, REJECTED,
aLocation);
learningRecordService.logRecord(aSessionOwner, record);

// Send an application event that the suggestion has been rejected
applicationEventPublisher.publishEvent(new RecommendationRejectedEvent(this, aDocument,
aDataOwner, suggestion.getBegin(), suggestion.getEnd(), suggestion.getCoveredText(),
feature, suggestion.getLabel()));
}

@Override
public void skipSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation)
throws AnnotationException
{
// 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.
aSuggestion.hide(FLAG_SKIPPED);

var recommender = recommendationService.getRecommender(aSuggestion);
var feature = recommender.getFeature();

// Log the action to the learning record
var record = toLearningRecord(aDocument, aDataOwner, aSuggestion, feature, SKIPPED,
aLocation);
learningRecordService.logRecord(aSessionOwner, record);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
package de.tudarmstadt.ukp.inception.recommendation.relation;

import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_OVERLAP;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_SKIPPED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_TRANSIENT_REJECTED;
import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.FEAT_REL_SOURCE;
import static de.tudarmstadt.ukp.inception.support.WebAnnoConst.FEAT_REL_TARGET;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -206,33 +204,6 @@ else if (candidates.size() > 1) {
return annotation;
}

@Override
public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction)
{
// 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.
aSuggestion.hide(FLAG_TRANSIENT_REJECTED);

// TODO: See span recommendation support...

}

@Override
public void skipSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aAction)
throws AnnotationException
{
// 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.
aSuggestion.hide(FLAG_SKIPPED);

// TODO: Log rejection
// TODO: Publish rejection event
}

@Override
public <T extends AnnotationSuggestion> void calculateSuggestionVisibility(String aSessionOwner,
SourceDocument aDocument, CAS aCas, String aUser, AnnotationLayer aLayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
package de.tudarmstadt.ukp.inception.recommendation.span;

import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_OVERLAP;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_SKIPPED;
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 static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.SKIPPED;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.util.Comparator.comparingInt;
Expand Down Expand Up @@ -67,7 +63,6 @@
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.recommendation.api.SuggestionRenderer;
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;
Expand Down Expand Up @@ -174,48 +169,6 @@ else if (candidates.isEmpty() || aAdapter.getLayer().isAllowStacking()) {
return annotation;
}

@Override
public void rejectSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation)
{
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.
suggestion.hide(FLAG_TRANSIENT_REJECTED);

var recommender = recommendationService.getRecommender(suggestion);
var feature = recommender.getFeature();
// Log the action to the learning record
var record = toLearningRecord(aDocument, aDataOwner, aSuggestion, feature, REJECTED,
aLocation);
learningRecordService.logRecord(aSessionOwner, record);

// Send an application event that the suggestion has been rejected
applicationEventPublisher.publishEvent(new RecommendationRejectedEvent(this, aDocument,
aDataOwner, suggestion.getBegin(), suggestion.getEnd(), suggestion.getCoveredText(),
feature, suggestion.getLabel()));

}

@Override
public void skipSuggestion(String aSessionOwner, SourceDocument aDocument, String aDataOwner,
AnnotationSuggestion aSuggestion, LearningRecordChangeLocation aLocation)
throws AnnotationException
{
// 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.
aSuggestion.hide(FLAG_SKIPPED);

var recommender = recommendationService.getRecommender(aSuggestion);
var feature = recommender.getFeature();

// Log the action to the learning record
var record = toLearningRecord(aDocument, aDataOwner, aSuggestion, feature, SKIPPED,
aLocation);
learningRecordService.logRecord(aSessionOwner, record);
}

@Override
public <T extends AnnotationSuggestion> void calculateSuggestionVisibility(String aSessionOwner,
SourceDocument aDocument, CAS aCas, String aDataOwner, AnnotationLayer aLayer,
Expand Down

0 comments on commit bf47a1f

Please sign in to comment.