Skip to content

Commit

Permalink
Merge branch 'main' into refactoring/Upgrade-to-Spring-Boot-3
Browse files Browse the repository at this point in the history
* main: (39 commits)
  No issue: Try to get build work on Windows
  No issue: Added gitattributes file
  #4618 - Resizing a span does not update annotations on disk
  #4616 - Option to disable displaying suggestions in sidebar curation mode
  #4554 - Allow displaying comments from annotators on hover when curating using curation sidebar on the annotation page
  No issue: Try to get build work on Windows
  #4610 - Annotations are misaligned when PDF pages vary in dimensions
  #4611 - Run the three SPARQL queries in the concept linker in parallel
  No issue: Added gitattributes file
  No issue: Enable matrix build
  #4557 - Bulk process page should not show processes from other projects
  #4596 - Ability to temporarily suspend recommenders
  #4603 - Bulk actions in search sidebar should not be greyed-out when in sidebar curation mode
  #4602 - Project-specific user preferences may be saved without a user
  #4603 - Bulk actions in search sidebar should not be greyed-out when in sidebar curation mode
  #4602 - Project-specific user preferences may be saved without a user
  #4600 - Error when exporting project during preference phase
  No issue: Fix example CSS file for custom XML format which was actually an SCSS file
  #4583 - Ability to configure layer visibility via a sidebar
  Remove <Proxy> directive as it shouldn't be necessary
  ...

% Conflicts:
%	inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/service/DiamWebsocketController.java
%	inception/inception-kb/src/test/java/de/tudarmstadt/ukp/inception/kb/FullTextIndexUpgradeTest.java
%	inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/config/RecommenderServiceAutoConfiguration.java
%	inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/footer/RecommendationEventFooterPanel.java
%	inception/inception-ui-scheduling/src/main/java/de/tudarmstadt/ukp/inception/ui/scheduling/TaskMonitorPanel.java
%	inception/inception-websocket/pom.xml
  • Loading branch information
reckart committed Mar 11, 2024
2 parents 8822a49 + d3db389 commit 74431b7
Show file tree
Hide file tree
Showing 183 changed files with 3,986 additions and 1,629 deletions.
24 changes: 24 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Set the default behavior, in case people don't have core.autocrlf set.
# means that files that GIT determines to be text files, will be
# converted from CRLF -> LF upon being added to the repo, and
# converted from LF -> LF or CRLF when checked out (depending on the platform, I think)
# * text=auto

# We force LF for all text files because we have Checkstyle set up in such a way
# The "text" by itself says these files must be line-ending-conversion controlled on check-in / out
# The internal repo form for these is always lf,
# The eol=lf means on check-out do nothing, and on check-in, if the file has crlf, convert to lf
* text eol=lf
# *.sh text eol=lf

# Make sure that these files are treated as binary so that newlines are preserved.
# overrides GIT's determination if a file is text or not
*.bin binary
*.dump binary
*.xcas binary
*.xmi binary
# next is probably the default
*.pdf binary
*.ser binary
*.png binary
*.jpg binary
10 changes: 7 additions & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ on:

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
jdk: [17]

runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK ${{ matrix.jdk }}
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
cache: maven
- name: Build with Maven
Expand Down
8 changes: 8 additions & 0 deletions inception/inception-active-learning/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-support</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-preferences</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-support-bootstrap</artifactId>
Expand Down Expand Up @@ -97,6 +101,10 @@
<artifactId>commons-lang3</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import de.tudarmstadt.ukp.inception.active.learning.log.ActiveLearningSuggestionOfferedAdapter;
import de.tudarmstadt.ukp.inception.active.learning.sidebar.ActiveLearningSidebarFactory;
import de.tudarmstadt.ukp.inception.documents.api.DocumentService;
import de.tudarmstadt.ukp.inception.preferences.PreferencesService;
import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService;
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.recommendation.config.RecommenderServiceAutoConfiguration;
Expand Down Expand Up @@ -73,7 +74,8 @@ public ActiveLearningSuggestionOfferedAdapter activeLearningSuggestionOfferedAda

@Bean
public ActiveLearningSidebarFactory activeLearningSidebarFactory(
RecommendationService aRecommendationService)
RecommendationService aRecommendationService, PreferencesService aPreferencesService,
UserDao aUserService)
{
return new ActiveLearningSidebarFactory(aRecommendationService);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
</div>
<div class="scrolling card-body flex-v-container">

<span wicket:id="notAvailableNotice" class="flex-content no-data-notice">
<wicket:message key="notAvailableNotice"/>
</span>

<form wicket:id="sessionControlForm">
<div class="input-group">
<select class="form-select flex-content" wicket:id="selectLayer" data-container="body"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import static de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasAccessMode.SHARED_READ_ONLY_ACCESS;
import static de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasUpgradeMode.AUTO_CAS_UPGRADE;
import static de.tudarmstadt.ukp.inception.active.learning.sidebar.ActiveLearningUserStateMetaData.CURRENT_AL_USER_STATE;
import static de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService.KEY_RECOMMENDER_GENERAL_SETTINGS;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_REJECTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion.FLAG_SKIPPED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.ACCEPTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.CORRECTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction.REJECTED;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhen;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhenNot;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -92,6 +94,7 @@
import de.tudarmstadt.ukp.inception.bootstrap.BootstrapModalDialog;
import de.tudarmstadt.ukp.inception.documents.api.DocumentService;
import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler;
import de.tudarmstadt.ukp.inception.preferences.PreferencesService;
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;
Expand All @@ -100,7 +103,6 @@
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.SpanSuggestion;
import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionDocumentGroup;
import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionGroup;
Expand Down Expand Up @@ -172,7 +174,9 @@ public class ActiveLearningSidebar
private @SpringBean ApplicationEventPublisherHolder applicationEventPublisherHolder;
private @SpringBean UserDao userService;
private @SpringBean FeatureSupportRegistry featureSupportRegistry;
private @SpringBean PreferencesService preferencesService;

private IModel<Boolean> recommendersAvailable;
private IModel<List<LearningRecord>> learningRecords;
private CompoundPropertyModel<ActiveLearningServiceImpl.ActiveLearningUserState> alStateModel;

Expand Down Expand Up @@ -211,17 +215,26 @@ public ActiveLearningSidebar(String aId, IModel<AnnotatorState> aModel,

// Set up the AL state in the page if it is not already there or if for some reason the
// suggestions have completely disappeared (e.g. after a system restart)
AnnotatorState state = getModelObject();
Predictions predictions = state.getProject() != null
var state = getModelObject();
var predictions = state.getProject() != null
? recommendationService.getPredictions(state.getUser(), state.getProject())
: null;
if (aAnnotationPage.getMetaData(CURRENT_AL_USER_STATE) == null || predictions == null) {
ActiveLearningUserState alState = new ActiveLearningUserState();
var alState = new ActiveLearningUserState();
alState.setStrategy(new UncertaintySamplingStrategy());
alStateModel.setObject(alState);
}

add(sessionControlForm = createSessionControlForm());
recommendersAvailable = LoadableDetachableModel.of(this::isRecommendersAvailable);

var notAvailableNotice = new WebMarkupContainer("notAvailableNotice");
notAvailableNotice.add(visibleWhenNot(recommendersAvailable));
add(notAvailableNotice);

sessionControlForm = createSessionControlForm();
sessionControlForm.add(visibleWhen(() -> alStateModel.getObject().isDoExistRecommenders()
&& recommendersAvailable.getObject()));
add(sessionControlForm);

alMainContainer = new WebMarkupContainer(CID_MAIN_CONTAINER);
alMainContainer.setOutputMarkupId(true);
Expand All @@ -230,19 +243,48 @@ public ActiveLearningSidebar(String aId, IModel<AnnotatorState> aModel,
alMainContainer.add(clearSkippedRecommendationForm());
alMainContainer.add(createRecommendationOperationForm());
alMainContainer.add(createLearningHistory());
alMainContainer.add(visibleWhen(recommendersAvailable));
add(alMainContainer);

dialog = new BootstrapModalDialog(CID_CONFIRMATION_DIALOG);
dialog.trapFocus();
add(dialog);
}

@Override
protected void onDetach()
{
super.onDetach();
recommendersAvailable.detach();
}

private boolean isRecommendersAvailable()
{
var state = getModelObject();
var prefs = preferencesService.loadDefaultTraitsForProject(KEY_RECOMMENDER_GENERAL_SETTINGS,
state.getProject());

// Do not show predictions when viewing annotations of another user
if (!prefs.isShowRecommendationsWhenViewingOtherUser()
&& !Objects.equals(state.getUser(), userService.getCurrentUser())) {
return false;
}

// Do not show predictions when viewing annotations of curation user
if (!prefs.isShowRecommendationsWhenViewingCurationUser()
&& Objects.equals(state.getUser(), userService.getCurationUser())) {
return false;
}

return true;
}

private Label createNoRecommendersMessage()
{
if (!alStateModel.getObject().isSessionActive()) {
// Use the currently selected layer from the annotation detail editor panel as the
// default choice in the active learning mode.
List<AnnotationLayer> layersWithRecommenders = listLayersWithRecommenders();
var layersWithRecommenders = listLayersWithRecommenders();
if (layersWithRecommenders.contains(getModelObject().getDefaultAnnotationLayer())) {
alStateModel.getObject().setLayer(getModelObject().getDefaultAnnotationLayer());
}
Expand All @@ -258,7 +300,7 @@ else if (!layersWithRecommenders.isEmpty()) {
}
}

Label noRecommendersMessage = new Label(CID_NO_RECOMMENDERS, "None of the layers have any "
var noRecommendersMessage = new Label(CID_NO_RECOMMENDERS, "None of the layers have any "
+ "recommenders configured. Please set the recommenders first in the Project "
+ "Settings.");
noRecommendersMessage
Expand All @@ -268,9 +310,9 @@ else if (!layersWithRecommenders.isEmpty()) {

private Form<Void> createSessionControlForm()
{
Form<Void> form = new Form<>(CID_SESSION_CONTROL_FORM);
var form = new Form<Void>(CID_SESSION_CONTROL_FORM);

DropDownChoice<AnnotationLayer> layersDropdown = new DropDownChoice<>(CID_SELECT_LAYER);
var layersDropdown = new DropDownChoice<AnnotationLayer>(CID_SELECT_LAYER);
layersDropdown.setModel(alStateModel.bind("layer"));
layersDropdown.setChoices(LoadableDetachableModel.of(this::listLayersWithRecommenders));
layersDropdown.setChoiceRenderer(new LambdaChoiceRenderer<>(AnnotationLayer::getUiName));
Expand All @@ -284,7 +326,6 @@ private Form<Void> createSessionControlForm()
.add(visibleWhen(() -> !alStateModel.getObject().isSessionActive())));
form.add(new LambdaAjaxLink(CID_STOP_SESSION_BUTTON, this::actionStopSession)
.add(visibleWhen(() -> alStateModel.getObject().isSessionActive())));
form.add(visibleWhen(() -> alStateModel.getObject().isDoExistRecommenders()));

return form;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ delta=\u0394
history=History
session=Session
activeLearning=Active Learning
notAvailableNotice=Currently not available
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import org.apache.wicket.Component;
import org.apache.wicket.model.IModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;

import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasProvider;
import de.tudarmstadt.ukp.clarin.webanno.model.Project;
Expand All @@ -37,12 +37,12 @@
* {@link ActiveLearningAutoConfiguration#activeLearningSidebarFactory}.
* </p>
*/
@Order(4000)
public class ActiveLearningSidebarFactory
extends AnnotationSidebarFactory_ImplBase
{
private final RecommendationService recommendationService;

@Autowired
public ActiveLearningSidebarFactory(RecommendationService aRecommendationService)
{
recommendationService = aRecommendationService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ActiveLearningSidebarIcon(String aId, IModel<AnnotatorState> aState)

setOutputMarkupId(true);

queue(new Icon("icon", FontAwesome5IconType.robot_s));
queue(new Icon("icon", FontAwesome5IconType.font_s));
queue(new Icon("badge", LoadableDetachableModel.of(this::getStateIcon))
.add(new ClassAttributeModifier()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.DoubleStream;

import de.tudarmstadt.ukp.clarin.webanno.agreement.results.coding.FullCodingAgreementResult;
import de.tudarmstadt.ukp.clarin.webanno.agreement.results.unitizing.FullUnitizingAgreementResult;
Expand Down Expand Up @@ -124,10 +125,10 @@ public void merge(AgreementSummary aResult)
}

for (var e : aResult.allNull.entrySet()) {
allNull.merge(e.getKey(), e.getValue(), Boolean::logicalOr);
allNull.merge(e.getKey(), e.getValue(), Boolean::logicalAnd);
}

empty |= aResult.empty;
empty &= aResult.empty;

if (incompleteSetsByPosition >= 0 && aResult.incompleteSetsByPosition >= 0) {
incompleteSetsByPosition += aResult.incompleteSetsByPosition;
Expand Down Expand Up @@ -208,9 +209,26 @@ public List<String> getCasGroupIds()
return casGroupIds;
}

private DoubleStream usableAgreements()
{
return agreements.stream() //
.mapToDouble(a -> a) //
.filter(v -> !Double.isNaN(v)); // skip documents for which we have no agreement
}

public double getAgreement()
{
return agreements.stream().mapToDouble(a -> a).average().orElse(Double.NaN);
return usableAgreements().average().orElse(Double.NaN);
}

public long getTotalAgreementsCount()
{
return agreements.size();
}

public long getUsableAgreementsCount()
{
return usableAgreements().count();
}

public String getType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ else if ((incLabel + incPos) == result.getRelevantSetCount()) {

var tooltipTitle = aRater1.getUiName() + " ↔ " + aRater2.getUiName();

var tooltipContent = "Positions annotated:\n"
var tooltipContent = String.format("Documents counted: %d/%d%n",
result.getUsableAgreementsCount(), result.getTotalAgreementsCount())
+ "Positions annotated:\n"
+ String.format("- %s: %d/%d%n", aRater1.getUiName(),
result.getNonNullCount(casGroupId1), result.getItemCount(casGroupId1))
+ String.format("- %s: %d/%d%n", aRater2.getUiName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ else if (noDataRater2) {

var tooltipTitle = aRater1.getUiName() + " ↔ " + aRater2.getUiName();

var tooltipContent = "Positions annotated:\n"
var tooltipContent = String.format("Documents counted: %d/%d%n",
result.getUsableAgreementsCount(), result.getTotalAgreementsCount())
+ "Positions annotated:\n"
+ String.format("- %s: %d/%d%n", aRater1.getUiName(),
result.getNonNullCount(casGroupId1), result.getItemCount(casGroupId1))
+ String.format("- %s: %d/%d%n", aRater2.getUiName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,6 @@ Optional<Long> verifyCasTimestamp(SourceDocument aDocument, String aUser,
void forceActionOnCas(SourceDocument aDocument, String aUser, CasStorageServiceLoader aLoader,
CasStorageServiceAction aAction, boolean aSave)
throws IOException;

Optional<Long> getCasFileSize(SourceDocument aDocument, String aUser) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,25 @@ public boolean existsCas(SourceDocument aDocument, String aUser) throws IOExcept
}
}

@Override
public Optional<Long> getCasFileSize(SourceDocument aDocument, String aUser) throws IOException
{
Validate.notNull(aDocument, "Source document must be specified");
Validate.notBlank(aUser, "User must be specified");

// Ensure that the CAS is not being re-written and temporarily unavailable while we check
// for its existence
try (var access = new WithExclusiveAccess(aDocument, aUser)) {
return driver.getCasFileSize(aDocument, aUser);
}
catch (IOException e) {
throw e;
}
catch (Exception e) {
throw new IOException(e);
}
}

private class WithExclusiveAccess
implements AutoCloseable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ Optional<CasStorageMetadata> getCasMetadata(SourceDocument aDocument, String aUs
Optional<Long> verifyCasTimestamp(SourceDocument aDocument, String aUser,
long aExpectedTimeStamp, String aContextAction)
throws IOException, ConcurentCasModificationException;

Optional<Long> getCasFileSize(SourceDocument aDocument, String aUser) throws IOException;
}
Loading

0 comments on commit 74431b7

Please sign in to comment.