Skip to content

Commit

Permalink
#2696 - Document-level recommendations
Browse files Browse the repository at this point in the history
- Cleaning up document metadata sidebar code
  • Loading branch information
reckart committed Dec 8, 2023
1 parent 6db8d1f commit d5e6d3b
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 96 deletions.
4 changes: 4 additions & 0 deletions inception/inception-layer-docmetadata/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-log</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-recommendation-api</artifactId>
</dependency>

<dependency>
<groupId>org.apache.uima</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
import de.tudarmstadt.ukp.clarin.webanno.model.Tag;
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage;
import de.tudarmstadt.ukp.inception.annotation.feature.link.LinkFeatureDeletedEvent;
import de.tudarmstadt.ukp.inception.annotation.feature.link.LinkFeatureEditor;
Expand Down Expand Up @@ -88,13 +89,13 @@ public class DocumentMetadataAnnotationDetailPanel
private final CasProvider jcasProvider;
private final IModel<Project> project;
private final IModel<SourceDocument> sourceDocument;
private final IModel<String> username;
private final IModel<User> user;
private final ListView<FeatureState> featureList;
private final AnnotationActionHandler actionHandler;
private final AnnotatorState state;

public DocumentMetadataAnnotationDetailPanel(String aId, IModel<VID> aModel,
IModel<SourceDocument> aDocument, IModel<String> aUsername, CasProvider aCasProvider,
IModel<SourceDocument> aDocument, IModel<User> aUser, CasProvider aCasProvider,
IModel<Project> aProject, AnnotationPage aAnnotationPage,
AnnotationActionHandler aActionHandler, AnnotatorState aState)
{
Expand All @@ -103,7 +104,7 @@ public DocumentMetadataAnnotationDetailPanel(String aId, IModel<VID> aModel,
setOutputMarkupPlaceholderTag(true);

sourceDocument = aDocument;
username = aUsername;
user = aUser;
annotationPage = aAnnotationPage;
jcasProvider = aCasProvider;
project = aProject;
Expand Down Expand Up @@ -324,8 +325,8 @@ private void writeFeatureEditorModelsToCas(TypeAdapter aAdapter, CAS aCas)

LOG.trace("writeFeatureEditorModelsToCas() " + featureState.feature.getUiName() + " = "
+ featureState.value);
aAdapter.setFeatureValue(sourceDocument.getObject(), username.getObject(), aCas,
getModelObject().getId(), featureState.feature, featureState.value);
aAdapter.setFeatureValue(sourceDocument.getObject(), user.getObject().getUsername(),
aCas, getModelObject().getId(), featureState.feature, featureState.value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
</div>
</div>
</div>
<div class="d-flex align-items-center">
<div class="d-flex align-items-center ms-2">
<button wicket:id="delete" type="button" class="btn btn-sm btn-danger">
<i class="fas fa-trash"></i>
<i class="fas fa-trash"/>
</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,20 @@
*/
package de.tudarmstadt.ukp.inception.ui.core.docanno.sidebar;

import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CLICK;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.enabledWhen;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhen;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.uima.UIMAException;
import org.apache.uima.cas.AnnotationBaseFS;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.FeatureStructure;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.feedback.IFeedback;
import org.apache.wicket.markup.html.WebMarkupContainer;
Expand All @@ -55,22 +51,22 @@

import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase;
import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasProvider;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer;
import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage;
import de.tudarmstadt.ukp.inception.annotation.events.FeatureValueUpdatedEvent;
import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler;
import de.tudarmstadt.ukp.inception.rendering.Renderer;
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState;
import de.tudarmstadt.ukp.inception.rendering.vmodel.VID;
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;
import de.tudarmstadt.ukp.inception.schema.api.feature.TypeUtil;
import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupport;
import de.tudarmstadt.ukp.inception.schema.api.layer.LayerSupportRegistry;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxEventBehavior;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormComponentUpdatingBehavior;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxLink;
import de.tudarmstadt.ukp.inception.support.uima.ICasUtil;
Expand All @@ -97,12 +93,13 @@ public class DocumentMetadataAnnotationSelectionPanel

private @SpringBean LayerSupportRegistry layerSupportRegistry;
private @SpringBean AnnotationSchemaService annotationService;
private @SpringBean RecommendationService recommendationService;

private final AnnotationPage annotationPage;
private final CasProvider jcasProvider;
private final IModel<Project> project;
private final IModel<SourceDocument> sourceDocument;
private final IModel<String> username;
private final IModel<User> user;
private final IModel<AnnotationLayer> selectedLayer;
private final IModel<List<AnnotationListItem>> annotations;
private final WebMarkupContainer annotationsContainer;
Expand All @@ -113,7 +110,7 @@ public class DocumentMetadataAnnotationSelectionPanel
private final AnnotatorState state;

public DocumentMetadataAnnotationSelectionPanel(String aId, IModel<Project> aProject,
IModel<SourceDocument> aDocument, IModel<String> aUsername, CasProvider aCasProvider,
IModel<SourceDocument> aDocument, IModel<User> aUser, CasProvider aCasProvider,
AnnotationPage aAnnotationPage, AnnotationActionHandler aActionHandler,
AnnotatorState aState)
{
Expand All @@ -123,17 +120,16 @@ public DocumentMetadataAnnotationSelectionPanel(String aId, IModel<Project> aPro

annotationPage = aAnnotationPage;
sourceDocument = aDocument;
username = aUsername;
user = aUser;
jcasProvider = aCasProvider;
project = aProject;
selectedLayer = Model.of(listCreatableMetadataLayers().stream().findFirst().orElse(null));
IModel<List<AnnotationLayer>> availableLayers = LoadableDetachableModel
.of(this::listCreatableMetadataLayers);
var availableLayers = LoadableDetachableModel.of(this::listCreatableMetadataLayers);
actionHandler = aActionHandler;
state = aState;
annotations = LoadableDetachableModel.of(this::listAnnotations);

WebMarkupContainer content = new WebMarkupContainer("content");
var content = new WebMarkupContainer("content");
add(content);

annotationsContainer = new WebMarkupContainer(CID_ANNOTATIONS_CONTAINER);
Expand All @@ -144,7 +140,7 @@ public DocumentMetadataAnnotationSelectionPanel(String aId, IModel<Project> aPro
|| !annotations.map(List::isEmpty).orElse(true).getObject()));
content.add(annotationsContainer);

DropDownChoice<AnnotationLayer> layer = new DropDownChoice<>(CID_LAYER);
var layer = new DropDownChoice<AnnotationLayer>(CID_LAYER);
layer.setModel(selectedLayer);
layer.setChoices(availableLayers);
layer.setChoiceRenderer(new ChoiceRenderer<>("uiName"));
Expand All @@ -157,7 +153,7 @@ public DocumentMetadataAnnotationSelectionPanel(String aId, IModel<Project> aPro
.add(visibleWhen(
() -> !availableLayers.map(List::isEmpty).orElse(true).getObject())));

WebMarkupContainer noLayersWarning = new WebMarkupContainer("noLayersWarning");
var noLayersWarning = new WebMarkupContainer("noLayersWarning");
noLayersWarning
.add(visibleWhen(() -> availableLayers.map(List::isEmpty).orElse(true).getObject()
&& annotations.map(List::isEmpty).orElse(true).getObject()));
Expand All @@ -175,11 +171,10 @@ private void actionCreate(AjaxRequestTarget aTarget) throws AnnotationException,
try {
annotationPage.ensureIsEditable();

DocumentMetadataLayerAdapter adapter = (DocumentMetadataLayerAdapter) annotationService
var adapter = (DocumentMetadataLayerAdapter) annotationService
.getAdapter(selectedLayer.getObject());
CAS cas = jcasProvider.get();
AnnotationBaseFS fs = adapter.add(sourceDocument.getObject(), username.getObject(),
cas);
var cas = jcasProvider.get();
var fs = adapter.add(sourceDocument.getObject(), user.getObject().getUsername(), cas);

createdAnnotationAddress = fs.getAddress();
annotationPage.writeEditorCas(cas);
Expand All @@ -200,14 +195,14 @@ private void actionDelete(AjaxRequestTarget aTarget,
annotationPage.ensureIsEditable();

// Load the boiler-plate
CAS cas = jcasProvider.get();
FeatureStructure fs = ICasUtil.selectFsByAddr(cas,
aDetailPanel.getModelObject().getId());
AnnotationLayer layer = annotationService.findLayer(project.getObject(), fs);
TypeAdapter adapter = annotationService.getAdapter(layer);
var cas = jcasProvider.get();
var fs = ICasUtil.selectFsByAddr(cas, aDetailPanel.getModelObject().getId());
var layer = annotationService.findLayer(project.getObject(), fs);
var adapter = annotationService.getAdapter(layer);

// Perform actual actions
adapter.delete(sourceDocument.getObject(), username.getObject(), cas, new VID(fs));
adapter.delete(sourceDocument.getObject(), user.getObject().getUsername(), cas,
VID.of(fs));

// persist changes
annotationPage.writeEditorCas(cas);
Expand Down Expand Up @@ -275,26 +270,18 @@ protected void populateItem(ListItem<AnnotationListItem> aItem)
{
aItem.setModel(CompoundPropertyModel.of(aItem.getModel()));

VID vid = new VID(aItem.getModelObject().addr);
var vid = aItem.getModelObject().vid;

WebMarkupContainer container = new WebMarkupContainer("annotation");
var container = new WebMarkupContainer("annotation");
aItem.add(container);

DocumentMetadataAnnotationDetailPanel detailPanel = new DocumentMetadataAnnotationDetailPanel(
CID_ANNOTATION_DETAILS, Model.of(vid), sourceDocument, username,
jcasProvider, project, annotationPage, actionHandler, state);
var detailPanel = new DocumentMetadataAnnotationDetailPanel(CID_ANNOTATION_DETAILS,
Model.of(vid), sourceDocument, user, jcasProvider, project, annotationPage,
actionHandler, state);
aItem.add(detailPanel);

container.add(new AjaxEventBehavior("click")
{
private static final long serialVersionUID = 1L;

@Override
protected void onEvent(AjaxRequestTarget aTarget)
{
actionSelect(aTarget, container, detailPanel);
}
});
container.add(new LambdaAjaxEventBehavior(CLICK,
$ -> actionSelect($, container, detailPanel)));

detailPanel.add(visibleWhen(() -> isExpanded(aItem, container)));

Expand All @@ -304,12 +291,12 @@ protected void onEvent(AjaxRequestTarget aTarget)
selectedDetailPanel = detailPanel;
}

WebMarkupContainer close = new WebMarkupContainer("close");
var close = new WebMarkupContainer("close");
close.add(visibleWhen(() -> isExpanded(aItem, container)));
close.setOutputMarkupId(true);
container.add(close);

WebMarkupContainer open = new WebMarkupContainer("open");
var open = new WebMarkupContainer("open");
open.add(visibleWhen(() -> !isExpanded(aItem, container)));
open.setOutputMarkupId(true);
container.add(open);
Expand All @@ -319,11 +306,10 @@ protected void onEvent(AjaxRequestTarget aTarget)
.add(visibleWhen(() -> !aItem.getModelObject().singleton)));
container.setOutputMarkupId(true);

aItem.add(new LambdaAjaxLink(CID_DELETE,
_target -> actionDelete(_target, detailPanel))
.add(visibleWhen(() -> !aItem.getModelObject().singleton))
.add(enabledWhen(() -> annotationPage.isEditable()
&& !aItem.getModelObject().layer.isReadonly())));
aItem.add(new LambdaAjaxLink(CID_DELETE, $ -> actionDelete($, detailPanel))
.add(visibleWhen(() -> !aItem.getModelObject().singleton))
.add(enabledWhen(() -> annotationPage.isEditable()
&& !aItem.getModelObject().layer.isReadonly())));

aItem.setOutputMarkupId(true);
}
Expand All @@ -340,16 +326,16 @@ private List<AnnotationLayer> listMetadataLayers()
{
return annotationService.listAnnotationLayer(getModelObject()).stream()
.filter(layer -> DocumentMetadataLayerSupport.TYPE.equals(layer.getType())
&& layer.isEnabled())
.collect(Collectors.toList());
&& layer.isEnabled()) //
.toList();
}

private List<AnnotationLayer> listCreatableMetadataLayers()
{
return listMetadataLayers().stream() //
.filter(layer -> !layer.isReadonly()) //
.filter(layer -> !getLayerSupport(layer).readTraits(layer).isSingleton())
.collect(toList());
.filter(layer -> !getLayerSupport(layer).readTraits(layer).isSingleton()) //
.toList();
}

private DocumentMetadataLayerSupport getLayerSupport(AnnotationLayer aLayer)
Expand All @@ -368,24 +354,28 @@ private List<AnnotationListItem> listAnnotations()
return emptyList();
}

List<AnnotationListItem> items = new ArrayList<>();
for (AnnotationLayer layer : listMetadataLayers()) {
List<AnnotationFeature> features = annotationService.listSupportedFeatures(layer);
TypeAdapter adapter = annotationService.getAdapter(layer);
var items = new ArrayList<AnnotationListItem>();

for (var layer : listMetadataLayers()) {
var features = annotationService.listSupportedFeatures(layer);
var adapter = annotationService.getAdapter(layer);
LayerSupport<?, ?> layerSupport = layerSupportRegistry.getLayerSupport(layer);
Renderer renderer = layerSupport.createRenderer(layer,
var renderer = layerSupport.createRenderer(layer,
() -> annotationService.listAnnotationFeature(layer));
boolean singleton = getLayerSupport(layer).readTraits(layer).isSingleton();

for (FeatureStructure fs : cas.select(adapter.getAnnotationType(cas))) {
Map<String, String> renderedFeatures = renderer.renderLabelFeatureValues(adapter,
fs, features);
String labelText = TypeUtil.getUiLabelText(renderedFeatures);
items.add(
new AnnotationListItem(ICasUtil.getAddr(fs), labelText, layer, singleton));
var singleton = getLayerSupport(layer).readTraits(layer).isSingleton();

for (var fs : cas.select(adapter.getAnnotationType(cas))) {
var renderedFeatures = renderer.renderLabelFeatureValues(adapter, fs, features);
var labelText = TypeUtil.getUiLabelText(renderedFeatures);
items.add(new AnnotationListItem(VID.of(fs), labelText, layer, singleton));
}
}

var predictions = recommendationService.getPredictions(user.getObject(), getModelObject());
if (predictions != null) {
predictions.getPredictionsByDocument(sourceDocument.getObject().getName());
}

return items;
}

Expand All @@ -409,15 +399,6 @@ public void onFeatureValueUpdated(FeatureValueUpdatedEvent aEvent)
}
});

// // If a feature value is updated refresh the annotation list since it might mean that
// // a label has changed
// if (selectedAnnotation != null) {
// aEvent.getRequestTarget().add(selectedAnnotation);
// }
// if (selectedDetailPanel != null) {
// aEvent.getRequestTarget().add(selectedDetailPanel);
// }

findParent(AnnotationPageBase.class)
.actionRefreshDocument((aEvent.getRequestTarget().orElse(null)));
}
Expand Down Expand Up @@ -446,19 +427,20 @@ protected static void handleException(Component aComponent, AjaxRequestTarget aT
}
}

@SuppressWarnings("unused")
private class AnnotationListItem
implements Serializable
{
final int addr;
private static final long serialVersionUID = -8505492366690693091L;

final VID vid;
final String label;
final AnnotationLayer layer;
final boolean singleton;

public AnnotationListItem(int aAddr, String aLabel, AnnotationLayer aLayer,
public AnnotationListItem(VID aVid, String aLabel, AnnotationLayer aLayer,
boolean aSingleton)
{
super();
addr = aAddr;
vid = aVid;
label = aLabel;
layer = aLayer;
singleton = aSingleton;
Expand Down
Loading

0 comments on commit d5e6d3b

Please sign in to comment.