Skip to content

Commit

Permalink
#5325 - Simpler way of adding pre-defined knowledge bases
Browse files Browse the repository at this point in the history
- Added KnowledgeBaseInitializer interface
- Added "Add" button to the knowledge base list
  • Loading branch information
reckart committed Mar 2, 2025
1 parent 9843691 commit b09d7ca
Show file tree
Hide file tree
Showing 10 changed files with 1,719 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@
import static java.util.Collections.emptyList;

import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.Optional;

import org.eclipse.rdf4j.repository.config.RepositoryImplConfig;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.request.resource.ResourceReference;

import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.project.initializers.KnowledgeBaseInitializer;
import de.tudarmstadt.ukp.inception.kb.KnowledgeBaseService;
import de.tudarmstadt.ukp.inception.kb.config.KnowledgeBaseProperties;
import de.tudarmstadt.ukp.inception.kb.model.KnowledgeBase;
import de.tudarmstadt.ukp.inception.kb.yaml.KnowledgeBaseProfile;
import de.tudarmstadt.ukp.inception.project.api.ProjectInitializationRequest;
import de.tudarmstadt.ukp.inception.project.api.ProjectInitializer;
import de.tudarmstadt.ukp.inception.project.initializers.wikidatalinking.config.WikiDataLinkingProjectInitializersAutoConfiguration;

Expand All @@ -39,10 +44,13 @@
* </p>
*/
public class WikiDataKnowledgeBaseInitializer
implements ProjectInitializer
implements KnowledgeBaseInitializer
{
private static final String WIKIDATA_PROFILE = "wikidata";

private static final PackageResourceReference THUMBNAIL = new PackageResourceReference(
MethodHandles.lookup().lookupClass(), "WikiDataKnowledgeBaseInitializer.svg");

private final KnowledgeBaseService kbService;
private final KnowledgeBaseProfile wikidataProfile;
private final KnowledgeBaseProperties kbProperties;
Expand All @@ -68,6 +76,18 @@ public String getName()
return "Wikidata knowledge base";
}

@Override
public Optional<String> getDescription()
{
return Optional.ofNullable(wikidataProfile.getInfo().getDescription());
}

@Override
public Optional<ResourceReference> getThumbnail()
{
return Optional.of(THUMBNAIL);
}

@Override
public boolean applyByDefault()
{
Expand All @@ -87,16 +107,15 @@ public List<Class<? extends ProjectInitializer>> getDependencies()
}

@Override
public void configure(Project aProject) throws IOException
public void configure(ProjectInitializationRequest aRequest) throws IOException
{
// set all the fields according to the chosen profile
RepositoryImplConfig cfg = kbService
.getRemoteConfig(wikidataProfile.getAccess().getAccessUrl());
var cfg = kbService.getRemoteConfig(wikidataProfile.getAccess().getAccessUrl());

// sets root concepts list - if null then an empty list otherwise change the
// values to IRI and populate the list
KnowledgeBase kb = new KnowledgeBase();
kb.setProject(aProject);
var kb = new KnowledgeBase();
kb.setProject(aRequest.getProject());
kb.setReadOnly(true);
kb.setMaxResults(kbProperties.getDefaultMaxResults());
kb.setType(wikidataProfile.getType());
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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.clarin.webanno.project.initializers;

import java.util.Optional;

import org.apache.wicket.request.resource.ResourceReference;

import de.tudarmstadt.ukp.inception.project.api.ProjectInitializer;

public interface KnowledgeBaseInitializer
extends ProjectInitializer
{
default Optional<String> getDescription()
{
return Optional.empty();
}

default Optional<ResourceReference> getThumbnail()
{
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@
<wicket:panel>
<div class="flex-content card">
<div class="card-header">
<div wicket:id="dialog"/>
<wicket:message key="kb.knowledgebases"/>
<div class="actions">
<button wicket:id="new" class="btn btn-primary">
<i class="fas fa-plus-square"></i>
<div class="btn-action-label"><wicket:message key="create"/></div>
</button>
<button wicket:id="add" class="btn btn-primary btn-action">
<i class="fas fa-list"></i>&nbsp;
<wicket:message key="add"/>
</button>
</div>
</div>
<div class="card-body fit-child-snug">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,60 @@
*/
package de.tudarmstadt.ukp.inception.ui.kb.project;

import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhenNot;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

import java.lang.invoke.MethodHandles;
import java.util.List;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.feedback.IFeedback;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wicketstuff.event.annotation.OnEvent;

import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.project.initializers.KnowledgeBaseInitializer;
import de.tudarmstadt.ukp.clarin.webanno.ui.project.layers.LayerTemplateSelectedEvent;
import de.tudarmstadt.ukp.inception.bootstrap.BootstrapModalDialog;
import de.tudarmstadt.ukp.inception.kb.KnowledgeBaseService;
import de.tudarmstadt.ukp.inception.kb.model.KnowledgeBase;
import de.tudarmstadt.ukp.inception.project.api.ProjectInitializationRequest;
import de.tudarmstadt.ukp.inception.project.api.ProjectService;
import de.tudarmstadt.ukp.inception.schema.api.event.LayerConfigurationChangedEvent;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormComponentUpdatingBehavior;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxLink;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior;
import de.tudarmstadt.ukp.inception.support.spring.ApplicationEventPublisherHolder;
import de.tudarmstadt.ukp.inception.support.wicket.ListPanel_ImplBase;
import de.tudarmstadt.ukp.inception.support.wicket.OverviewListChoice;
import de.tudarmstadt.ukp.inception.ui.kb.project.wizard.KnowledgeBaseCreationDialog;

public class KnowledgeBaseListPanel
extends ListPanel_ImplBase
{
static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private static final long serialVersionUID = 8414963964131106164L;

private @SpringBean KnowledgeBaseService kbService;
private @SpringBean ProjectService projectService;
private @SpringBean ApplicationEventPublisherHolder applicationEventPublisherHolder;

private IModel<Project> projectModel;
private IModel<KnowledgeBase> kbModel;
private OverviewListChoice<KnowledgeBase> overviewList;
private final BootstrapModalDialog dialog;
private final LambdaAjaxLink addButton;

private KnowledgeBaseCreationDialog modal;
private final IModel<List<KnowledgeBaseInitializer>> knowledgeBaseInitializers;

public KnowledgeBaseListPanel(String id, IModel<Project> aProjectModel,
IModel<KnowledgeBase> aKbModel)
Expand All @@ -54,6 +81,18 @@ public KnowledgeBaseListPanel(String id, IModel<Project> aProjectModel,

kbModel = aKbModel;

knowledgeBaseInitializers = LoadableDetachableModel.of(this::listKnowledgeBaseInitializers);
add(LambdaBehavior.onDetach(knowledgeBaseInitializers::detach));

dialog = new BootstrapModalDialog("dialog");
dialog.trapFocus();
queue(dialog);

addButton = new LambdaAjaxLink("add", this::actionAddKnowledgeBase);
addButton.setOutputMarkupPlaceholderTag(true);
addButton.add(visibleWhenNot(knowledgeBaseInitializers.map(List::isEmpty)));
add(addButton);

projectModel = aProjectModel;
overviewList = new OverviewListChoice<>("knowledgebases");
overviewList.setChoiceRenderer(new ChoiceRenderer<>("name"));
Expand All @@ -68,9 +107,65 @@ public KnowledgeBaseListPanel(String id, IModel<Project> aProjectModel,
add(new LambdaAjaxLink("new", this::actionCreate));
}

public Project getModelObject()
{
return (Project) getDefaultModelObject();
}

@SuppressWarnings("unchecked")
public IModel<Project> getModel()
{
return (IModel<Project>) getDefaultModel();
}

@Override
protected void actionCreate(AjaxRequestTarget aTarget) throws Exception
{
modal.show(aTarget);
}

private List<KnowledgeBaseInitializer> listKnowledgeBaseInitializers()
{
if (getModelObject() == null) {
return emptyList();
}

return projectService.listProjectInitializers().stream()
.filter(initializer -> initializer instanceof KnowledgeBaseInitializer)
.map(KnowledgeBaseInitializer.class::cast)
.filter(initializer -> !initializer.alreadyApplied(getModelObject())).toList();
}

private void actionAddKnowledgeBase(AjaxRequestTarget aTarget)
{
var dialogContent = new KnowledgeBaseTemplateSelectionDialogPanel(
BootstrapModalDialog.CONTENT_ID, getModel(), knowledgeBaseInitializers);
dialog.open(dialogContent, aTarget);
}

@OnEvent
public void onLayerTemplateSelected(LayerTemplateSelectedEvent aEvent)
{
var target = aEvent.getTarget();
var initializer = aEvent.getLayerInitializer();
try {
// target.add(initializersContainer);
target.add(overviewList);
target.add(addButton);
target.addChildren(getPage(), IFeedback.class);
var request = ProjectInitializationRequest.builder() //
.withProject(getModelObject()) //
.build();
projectService.initializeProject(request, asList(initializer));
success("Applyed knowledge base initializer [" + initializer.getName() + "]");
}
catch (Exception e) {
error("Error applying knowledge base initializer [" + initializer.getName() + "]: "
+ ExceptionUtils.getRootCauseMessage(e));
LOG.error("Error applying knowledge base initializer {}", initializer, e);
}

applicationEventPublisherHolder.get()
.publishEvent(new LayerConfigurationChangedEvent(this, getModelObject()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.ui.kb.project;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.wicketstuff.event.annotation.AbstractAjaxAwareEvent;

import de.tudarmstadt.ukp.clarin.webanno.project.initializers.KnowledgeBaseInitializer;

public class KnowledgeBaseTemplateSelectedEvent
extends AbstractAjaxAwareEvent
{
private final KnowledgeBaseInitializer kbInitializer;

public KnowledgeBaseTemplateSelectedEvent(AjaxRequestTarget aTarget,
KnowledgeBaseInitializer aKBInitializer)
{
super(aTarget);

kbInitializer = aKBInitializer;
}

public KnowledgeBaseInitializer getKnowledgeBaseInitializer()
{
return kbInitializer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<!--
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.
-->
<html xmlns:wicket="http://wicket.apache.org">
<wicket:head>
<style>
.thumbnail {
height: auto;
object-fit: scale-down;
}
.thumbnail-wrapper {
height: 125px;
width: 125px;
}
.template-card {
transition: box-shadow .3s;
border-color: var(--bs-secondary-color) !important;
}

.template-card:hover {
box-shadow: 0 0 10px var(--bs-tertiary-color);
}
</style>
</wicket:head>
<wicket:panel>
<div class="modal-header">
<h5 class="modal-title">
<wicket:message key="addKnowledgeBaseDialogTitle"/>
</h5>
<button wicket:id="closeDialog" type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="modal-body overflow-auto pt-0">
<div wicket:id="container" class="row m-0 g-3">
<div wicket:id="templates" class="d-flex">
<button wicket:id="create" class="card template-card d-flex flex-row flex-grow-1 p-0 overflow-hidden">
<div class="bg-light d-flex flex-grow-0 align-content-center justify-content-center thumbnail-wrapper">
<img wicket:id="thumbnail" type="button" class="thumbnail">
</div>
<div class="card-body w-100">
<h5 wicket:id="name" class="card-title text-start"/>
<div class="card-text text-start">
<wicket:container wicket:id="description"/>
</div>
</div>
</button>
</div>
</div>
</div>
</wicket:panel>
</html>
Loading

0 comments on commit b09d7ca

Please sign in to comment.