Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preferences for Grobid #8002

Merged
merged 14 commits into from
Aug 21, 2021
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/JabRefMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private static void applyPreferences(PreferencesService preferences) {
Globals.journalAbbreviationRepository = JournalAbbreviationLoader.loadRepository(preferences.getJournalAbbreviationPreferences());

// Build list of Import and Export formats
Globals.IMPORT_FORMAT_READER.resetImportFormats(preferences.getImportFormatPreferences(),
Globals.IMPORT_FORMAT_READER.resetImportFormats(preferences.getImportSettingsPreferences(), preferences.getImportFormatPreferences(),
preferences.getXmpPreferences(), Globals.getFileUpdateMonitor());
Globals.entryTypesManager.addCustomOrModifiedTypes(preferences.getBibEntryTypes(BibDatabaseMode.BIBTEX),
preferences.getBibEntryTypes(BibDatabaseMode.BIBLATEX));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jabref.gui.bibtexextractor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.undo.UndoManager;
Expand Down Expand Up @@ -32,7 +33,7 @@ public class BibtexExtractorViewModel {

private final StringProperty inputTextProperty = new SimpleStringProperty("");
private final DialogService dialogService;
private final GrobidCitationFetcher currentCitationfetcher;
private final PreferencesService preferencesService;
private final TaskExecutor taskExecutor;
private final ImportHandler importHandler;

Expand All @@ -45,7 +46,7 @@ public BibtexExtractorViewModel(BibDatabaseContext bibdatabaseContext,
StateManager stateManager) {

this.dialogService = dialogService;
currentCitationfetcher = new GrobidCitationFetcher(preferencesService.getImportFormatPreferences());
this.preferencesService = preferencesService;
this.taskExecutor = taskExecutor;
this.importHandler = new ImportHandler(
bibdatabaseContext,
Expand All @@ -61,7 +62,22 @@ public StringProperty inputTextProperty() {
}

public void startParsing() {
BackgroundTask.wrap(() -> currentCitationfetcher.performSearch(inputTextProperty.getValue()))
if (preferencesService.getImportSettingsPreferences().isGrobidEnabled()) {
parseUsingGrobid();
} else {
parseUsingBibtexExtractor();
}
}

private void parseUsingBibtexExtractor() {
BibEntry parsedEntry = new BibtexExtractor().extract(inputTextProperty.getValue());
importHandler.importEntries(List.of(parsedEntry));
trackNewEntry(parsedEntry, "ParseWithBibTeXExtractor");
}

private void parseUsingGrobid() {
GrobidCitationFetcher grobidCitationFetcher = new GrobidCitationFetcher(preferencesService.getImportSettingsPreferences(), preferencesService.getImportFormatPreferences());
BackgroundTask.wrap(() -> grobidCitationFetcher.performSearch(inputTextProperty.getValue()))
.onRunning(() -> dialogService.notify(Localization.lang("Your text is being parsed...")))
.onFailure((e) -> {
if (e instanceof FetcherException) {
Expand All @@ -76,14 +92,14 @@ public void startParsing() {
dialogService.notify(Localization.lang("%0 entries were parsed from your query.", String.valueOf(parsedEntries.size())));
importHandler.importEntries(parsedEntries);
for (BibEntry bibEntry : parsedEntries) {
trackNewEntry(bibEntry);
trackNewEntry(bibEntry, "ParseWithGrobid");
}
}).executeWith(taskExecutor);
}

private void trackNewEntry(BibEntry bibEntry) {
private void trackNewEntry(BibEntry bibEntry, String eventMessage) {
Map<String, String> properties = new HashMap<>();
properties.put("EntryType", bibEntry.typeProperty().getValue().getName());
Globals.getTelemetryClient().ifPresent(client -> client.trackEvent("ParseWithGrobid", properties, new HashMap<>()));
Globals.getTelemetryClient().ifPresent(client -> client.trackEvent(eventMessage, properties, new HashMap<>()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.jabref.gui.DialogService;
import org.jabref.gui.StateManager;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.importer.GrobidOptInDialogHelper;

import com.airhacks.afterburner.injection.Injector;

Expand All @@ -17,6 +18,7 @@ public ExtractBibtexAction(StateManager stateManager) {
@Override
public void execute() {
DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
GrobidOptInDialogHelper.showAndWaitIfUserIsUndecided(dialogService);
dialogService.showCustomDialogAndWait(new ExtractBibtexDialog());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ExtractBibtexDialog() {

buttonParse = (Button) getDialogPane().lookupButton(parseButtonType);
buttonParse.setTooltip(new Tooltip((Localization.lang("Starts the extraction and adds the resulting entries to the currently opened database"))));
buttonParse.setOnAction(event -> viewModel.startParsing());
buttonParse.setOnAction((event) -> viewModel.startParsing());
buttonParse.disableProperty().bind(viewModel.inputTextProperty().isEmpty());
}

Expand Down
16 changes: 14 additions & 2 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.jabref.gui.externalfiles.ExternalFilesEntryLinker;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.help.HelpAction;
import org.jabref.gui.importer.GrobidOptInDialogHelper;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.menus.ChangeEntryTypeMenu;
import org.jabref.gui.mergeentries.FetchAndMergeEntry;
Expand All @@ -45,6 +46,7 @@
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.EntryBasedFetcher;
import org.jabref.logic.importer.WebFetchers;
import org.jabref.logic.importer.fileformat.PdfMergeMetadataImporter;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.Field;
Expand Down Expand Up @@ -355,11 +357,21 @@ private void setupToolBar() {

// Add menu for fetching bibliographic information
ContextMenu fetcherMenu = new ContextMenu();
for (EntryBasedFetcher fetcher : WebFetchers.getEntryBasedFetchers(preferencesService.getImportFormatPreferences(), preferencesService.getFilePreferences(), databaseContext, preferencesService.getDefaultEncoding())) {
for (EntryBasedFetcher fetcher : WebFetchers.getEntryBasedFetchers(preferencesService.getImportSettingsPreferences(), preferencesService.getImportFormatPreferences(), preferencesService.getFilePreferences(), databaseContext, preferencesService.getDefaultEncoding())) {
btut marked this conversation as resolved.
Show resolved Hide resolved
MenuItem fetcherMenuItem = new MenuItem(fetcher.getName());
fetcherMenuItem.setOnAction(event -> fetchAndMerge(fetcher));
if (fetcher instanceof PdfMergeMetadataImporter.EntryBasedFetcherWrapper) {
// Handle Grobid Opt-In in case of the PdfMergeMetadataImporter
fetcherMenuItem.setOnAction(event -> {
GrobidOptInDialogHelper.showAndWaitIfUserIsUndecided(dialogService);
PdfMergeMetadataImporter.EntryBasedFetcherWrapper pdfMergeMetadataImporter = new PdfMergeMetadataImporter.EntryBasedFetcherWrapper(preferencesService.getImportSettingsPreferences(), preferencesService.getImportFormatPreferences(), preferencesService.getFilePreferences(), databaseContext, preferencesService.getDefaultEncoding());
btut marked this conversation as resolved.
Show resolved Hide resolved
fetchAndMerge(pdfMergeMetadataImporter);
});
} else {
fetcherMenuItem.setOnAction(event -> fetchAndMerge(fetcher));
}
fetcherMenu.getItems().add(fetcherMenuItem);
}

fetcherButton.setOnMouseClicked(event -> fetcherMenu.show(fetcherButton, Side.RIGHT, 0, 0));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public ImportHandler(BibDatabaseContext database,
this.stateManager = stateManager;

this.linker = new ExternalFilesEntryLinker(externalFileTypes, preferencesService.getFilePreferences(), database);
this.contentImporter = new ExternalFilesContentImporter(preferencesService.getImportFormatPreferences(), preferencesService.getTimestampPreferences());
this.contentImporter = new ExternalFilesContentImporter(preferencesService.getImportSettingsPreferences(), preferencesService.getImportFormatPreferences(), preferencesService.getTimestampPreferences());
btut marked this conversation as resolved.
Show resolved Hide resolved
this.undoManager = undoManager;
}

Expand Down
38 changes: 38 additions & 0 deletions src/main/java/org/jabref/gui/importer/GrobidOptInDialogHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.jabref.gui.importer;

import org.jabref.gui.DialogService;
import org.jabref.gui.Globals;
import org.jabref.logic.l10n.Localization;
import org.jabref.preferences.PreferencesService;

/**
* Metadata extraction from PDFs and plaintext works very well using Grobid, but we do not want to enable it by default
* due to data privacy concerns.
* To make users aware of the feature, we ask each time before querrying Grobid, giving the option to opt-out.
*/
public class GrobidOptInDialogHelper {

/**
* If Grobid is not enabled but the user has not expicitly opted-out of Grobid, we ask for permission to send data
* to Grobid using a dialog and giving an opt-out option.
* @param dialogService the DialogService to use
* @return if the user enabled Grobid, either in the past or after being asked by the dialog.
*/
public static boolean showAndWaitIfUserIsUndecided(DialogService dialogService) {
PreferencesService preferences = Globals.prefs;
if (preferences.getImportSettingsPreferences().isGrobidEnabled()) {
return true;
}
if (preferences.getImportSettingsPreferences().isGrobidOptOut()) {
return false;
}
boolean grobidEnabled = dialogService.showConfirmationDialogWithOptOutAndWait(
Localization.lang("Remote services"),
Localization.lang("Allow sending PDF files and raw citation strings to a JabRef online service (Grobid) to determine Metadata. This produces better results."),
Localization.lang("Do not ask again"),
(optOut) -> preferences.storeImportSettingsPreferences(preferences.getImportSettingsPreferences().withGrobidOptOut(optOut))
);
preferences.storeImportSettingsPreferences(preferences.getImportSettingsPreferences().withGrobidEnabled(grobidEnabled));
return grobidEnabled;
}
}
23 changes: 21 additions & 2 deletions src/main/java/org/jabref/gui/importer/ImportAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@
import org.jabref.logic.importer.ImportFormatReader;
import org.jabref.logic.importer.Importer;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.importer.fileformat.PdfGrobidImporter;
import org.jabref.logic.importer.fileformat.PdfMergeMetadataImporter;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.StandardFileType;
import org.jabref.logic.util.UpdateField;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.util.FileHelper;
import org.jabref.preferences.PreferencesService;

import org.slf4j.Logger;
Expand Down Expand Up @@ -101,18 +105,33 @@ public void automatedImport(List<String> filenames) {
}
}

private boolean fileIsPdf(Path filename) {
Optional<String> extension = FileHelper.getFileExtension(filename);
return extension.isPresent() && StandardFileType.PDF.getExtensions().contains(extension.get());
}

private List<ImportFormatReader.UnknownFormatImport> doImport(List<Path> files) {
// We import all files and collect their results:
List<ImportFormatReader.UnknownFormatImport> imports = new ArrayList<>();
for (Path filename : files) {
try {
if (importer.isEmpty()) {
// Unknown format:
DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().notify(Localization.lang("Importing in unknown format") + "..."));
DefaultTaskExecutor.runAndWaitInJavaFXThread(() -> {
if (fileIsPdf(filename) && GrobidOptInDialogHelper.showAndWaitIfUserIsUndecided(frame.getDialogService())) {
Globals.IMPORT_FORMAT_READER.resetImportFormats(prefs.getImportSettingsPreferences(), prefs.getImportFormatPreferences(), prefs.getXmpPreferences(), Globals.getFileUpdateMonitor());
}
frame.getDialogService().notify(Localization.lang("Importing in unknown format") + "...");
});
// This import method never throws an IOException:
imports.add(Globals.IMPORT_FORMAT_READER.importUnknownFormat(filename, prefs.getTimestampPreferences(), Globals.getFileUpdateMonitor()));
} else {
DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().notify(Localization.lang("Importing in %0 format", importer.get().getName()) + "..."));
DefaultTaskExecutor.runAndWaitInJavaFXThread(() -> {
if (importer.get() instanceof PdfGrobidImporter || importer.get() instanceof PdfMergeMetadataImporter && GrobidOptInDialogHelper.showAndWaitIfUserIsUndecided(frame.getDialogService())) {
Globals.IMPORT_FORMAT_READER.resetImportFormats(prefs.getImportSettingsPreferences(), prefs.getImportFormatPreferences(), prefs.getXmpPreferences(), Globals.getFileUpdateMonitor());
}
frame.getDialogService().notify(Localization.lang("Importing in %0 format", importer.get().getName()) + "...");
});
// Specific importer:
ParserResult pr = importer.get().importDatabase(filename, Globals.prefs.getDefaultEncoding());
imports.add(new ImportFormatReader.UnknownFormatImport(importer.get().getName(), pr));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public void storeSettings() {
.map(ImporterViewModel::getLogic)
.collect(Collectors.toSet()));
Globals.IMPORT_FORMAT_READER.resetImportFormats(
preferences.getImportSettingsPreferences(),
preferences.getImportFormatPreferences(),
preferences.getXmpPreferences(),
Globals.getFileUpdateMonitor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,11 @@

<Label styleClass="sectionHeader" text="%Export sort order"/>
<SaveOrderConfigPanel fx:id="exportOrderPanel"/>

<Label styleClass="sectionHeader" text="%Remote services"/>
<CheckBox fx:id="grobidEnabled" text="%Allow sending PDF files and raw citation strings to a JabRef online service (Grobid) to determine Metadata. This produces better results."/>
<HBox alignment="CENTER_LEFT" spacing="10.0">
<Label text="%Grobid URL" />
<TextField fx:id="grobidURL" HBox.hgrow="ALWAYS"/>
</HBox>
</fx:root>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public class ImportExportTab extends AbstractPreferenceTabView<ImportExportTabVi

@FXML private SaveOrderConfigPanel exportOrderPanel;

@FXML private CheckBox grobidEnabled;
@FXML private TextField grobidURL;

public ImportExportTab() {
ViewLoader.view(this)
.root(this)
Expand All @@ -45,5 +48,9 @@ public void initialize() {
exportOrderPanel.sortableFieldsProperty().bind(viewModel.sortableFieldsProperty());
exportOrderPanel.sortCriteriaProperty().bindBidirectional(viewModel.sortCriteriaProperty());
exportOrderPanel.setCriteriaLimit(3);

grobidEnabled.selectedProperty().bindBidirectional(viewModel.grobidEnabledProperty());
grobidURL.textProperty().bindBidirectional(viewModel.grobidURLProperty());
grobidURL.disableProperty().bind(grobidEnabled.selectedProperty().not());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be done in directly in FXML. (disabled=${grobidEnabled.selected}) or similar. Lot's of examples elsewhere...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's possible here because you can't do the negation in fxml. It needs to be disabled if grobidEnabled is NOT selected.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class ImportExportTabViewModel implements PreferenceTabViewModel {
private final ListProperty<Field> sortableFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
private final ListProperty<SortCriterionViewModel> sortCriteriaProperty = new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>()));

private final BooleanProperty grobidEnabledProperty = new SimpleBooleanProperty();
private final StringProperty grobidURLProperty = new SimpleStringProperty("");

private final PreferencesService preferencesService;
private final DOIPreferences initialDOIPreferences;
private final ImportSettingsPreferences initialImportSettingsPreferences;
Expand Down Expand Up @@ -67,12 +70,15 @@ public void setValues() {
sortCriteriaProperty.addAll(initialExportOrder.getSortCriteria().stream()
.map(SortCriterionViewModel::new)
.collect(Collectors.toList()));

grobidEnabledProperty.setValue(initialImportSettingsPreferences.isGrobidEnabled());
grobidURLProperty.setValue(initialImportSettingsPreferences.getGrobidURL());
}

@Override
public void storeSettings() {
preferencesService.storeImportSettingsPreferences(new ImportSettingsPreferences(
generateKeyOnImportProperty.getValue()));
generateKeyOnImportProperty.getValue(), grobidEnabledProperty.getValue(), preferencesService.getImportSettingsPreferences().isGrobidOptOut(), grobidURLProperty.getValue()));

preferencesService.storeDOIPreferences(new DOIPreferences(
useCustomDOIProperty.getValue(),
Expand Down Expand Up @@ -118,4 +124,12 @@ public ListProperty<Field> sortableFieldsProperty() {
public ListProperty<SortCriterionViewModel> sortCriteriaProperty() {
return sortCriteriaProperty;
}

public BooleanProperty grobidEnabledProperty() {
return grobidEnabledProperty;
}

public StringProperty grobidURLProperty() {
return grobidURLProperty;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,25 @@
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.importer.fileformat.PdfMergeMetadataImporter;
import org.jabref.logic.importer.fileformat.PdfXmpImporter;
import org.jabref.logic.importer.importsettings.ImportSettingsPreferences;
import org.jabref.logic.preferences.TimestampPreferences;
import org.jabref.model.util.FileUpdateMonitor;

public class ExternalFilesContentImporter {

private final ImportSettingsPreferences importSettingsPreferences;
private final ImportFormatPreferences importFormatPreferences;
private final TimestampPreferences timestampPreferences;

public ExternalFilesContentImporter(ImportFormatPreferences importFormatPreferences, TimestampPreferences timestampPreferences) {
public ExternalFilesContentImporter(ImportSettingsPreferences importSettingsPreferences, ImportFormatPreferences importFormatPreferences, TimestampPreferences timestampPreferences) {
this.importSettingsPreferences = importSettingsPreferences;
this.importFormatPreferences = importFormatPreferences;
this.timestampPreferences = timestampPreferences;
}

public ParserResult importPDFContent(Path file) {
try {
return new PdfMergeMetadataImporter(importFormatPreferences).importDatabase(file, StandardCharsets.UTF_8);
return new PdfMergeMetadataImporter(importSettingsPreferences, importFormatPreferences).importDatabase(file, StandardCharsets.UTF_8);
} catch (IOException e) {
return ParserResult.fromError(e);
}
Expand Down
Loading