Skip to content

Commit

Permalink
Add plain citation parsing with LLM
Browse files Browse the repository at this point in the history
  • Loading branch information
InAnYan committed Sep 25, 2024
1 parent 91d0709 commit 7d0c04f
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@

import javax.swing.undo.UndoManager;

import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;

import org.jabref.gui.DialogService;
import org.jabref.gui.StateManager;
import org.jabref.gui.externalfiles.ImportHandler;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.ai.AiService;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.fetcher.GrobidCitationFetcher;
import org.jabref.logic.importer.fetcher.LlmCitationFetcher;
import org.jabref.logic.importer.fetcher.OnlinePlainCitationParser;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.util.BackgroundTask;
Expand All @@ -35,23 +43,29 @@ public class BibtexExtractorViewModel {
private static final Logger LOGGER = LoggerFactory.getLogger(BibtexExtractorViewModel.class);

private final boolean onlineMode;

private final DialogService dialogService;
private final AiService aiService;
private final CliPreferences preferences;
private final TaskExecutor taskExecutor;

private final ImportHandler importHandler;
private final StringProperty inputTextProperty = new SimpleStringProperty("");
private final ListProperty<OnlinePlainCitationParser> onlinePlainCitationParsers = new SimpleListProperty<>(FXCollections.observableArrayList(OnlinePlainCitationParser.values()));
private final ObjectProperty<OnlinePlainCitationParser> parserChoice;

public BibtexExtractorViewModel(boolean onlineMode,
BibDatabaseContext bibdatabaseContext,
DialogService dialogService,
AiService aiService,
GuiPreferences preferences,
FileUpdateMonitor fileUpdateMonitor,
TaskExecutor taskExecutor,
UndoManager undoManager,
StateManager stateManager) {
this.onlineMode = onlineMode;
this.dialogService = dialogService;
this.aiService = aiService;
this.preferences = preferences;
this.taskExecutor = taskExecutor;
this.importHandler = new ImportHandler(
Expand All @@ -62,6 +76,8 @@ public BibtexExtractorViewModel(boolean onlineMode,
stateManager,
dialogService,
taskExecutor);

this.parserChoice = new SimpleObjectProperty<>(preferences.getImporterPreferences().defaultOnlinePlainCitationParserProperty().get());
}

public void startParsing() {
Expand All @@ -78,25 +94,38 @@ private void startParsingOffline() {
}

private void startParsingOnline() {
GrobidCitationFetcher grobidCitationFetcher = new GrobidCitationFetcher(preferences.getGrobidPreferences(), preferences.getImportFormatPreferences());
BackgroundTask.wrap(() -> grobidCitationFetcher.performSearch(inputTextProperty.getValue()))
.onRunning(() -> dialogService.notify(Localization.lang("Your text is being parsed...")))
.onFailure(e -> {
if (e instanceof FetcherException) {
String msg = Localization.lang("There are connection issues with a JabRef server. Detailed information: %0",
e.getMessage());
dialogService.notify(msg);
} else {
LOGGER.warn("Missing exception handling.", e);
}
})
.onSuccess(parsedEntries -> {
dialogService.notify(Localization.lang("%0 entries were parsed from your query.", String.valueOf(parsedEntries.size())));
importHandler.importEntries(parsedEntries);
}).executeWith(taskExecutor);
BackgroundTask
.wrap(() -> switch (parserChoice.get()) {
case GROBID ->
new GrobidCitationFetcher(preferences.getGrobidPreferences(), preferences.getImportFormatPreferences()).performSearch(inputTextProperty.getValue());
case LLM ->
new LlmCitationFetcher(preferences.getImportFormatPreferences(), aiService.getChatLanguageModel()).performSearch(inputTextProperty.getValue());
})
.onRunning(() -> dialogService.notify(Localization.lang("Your text is being parsed...")))
.onFailure(e -> {
if (e instanceof FetcherException) {
String msg = Localization.lang("There are connection issues with a JabRef server. Detailed information: %0",
e.getMessage());
dialogService.notify(msg);
} else {
LOGGER.warn("Missing exception handling.", e);
}
})
.onSuccess(parsedEntries -> {
dialogService.notify(Localization.lang("%0 entries were parsed from your query.", String.valueOf(parsedEntries.size())));
importHandler.importEntries(parsedEntries);
}).executeWith(taskExecutor);
}

public StringProperty inputTextProperty() {
return this.inputTextProperty;
}

public ListProperty<OnlinePlainCitationParser> onlinePlainCitationParsers() {
return this.onlinePlainCitationParsers;
}

public ObjectProperty<OnlinePlainCitationParser> parserChoice() {
return this.parserChoice;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ComboBox?>
<DialogPane prefHeight="430.0" prefWidth="586.0" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jabref.gui.bibtexextractor.ExtractBibtexDialog">
<content>
<VBox fx:id="contentVbox" minHeight="-Infinity" prefHeight="200.0" prefWidth="100.0">
<VBox fx:id="contentVbox" spacing="10" minHeight="-Infinity" prefHeight="200.0" prefWidth="100.0">
<children>
<TextArea fx:id="input" minHeight="-Infinity" prefHeight="350.0" prefWidth="586.0" wrapText="true"/>
<TextArea fx:id="input" minHeight="-Infinity" prefHeight="450.0" prefWidth="586.0" wrapText="true"/>
<HBox alignment="BASELINE_LEFT" spacing="10">
<children>
<Label text="%Parser choice (only for online extraction):"/>
<ComboBox fx:id="parserChoice" HBox.hgrow="ALWAYS"/>
</children>
</HBox>
</children>
</VBox>
</content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextArea;
import javafx.scene.control.Tooltip;

Expand All @@ -14,6 +15,9 @@
import org.jabref.gui.StateManager;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.gui.util.BaseDialog;
import org.jabref.gui.util.ViewModelListCellFactory;
import org.jabref.logic.ai.AiService;
import org.jabref.logic.importer.fetcher.OnlinePlainCitationParser;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.TaskExecutor;
import org.jabref.model.database.BibDatabaseContext;
Expand All @@ -34,21 +38,25 @@ public class ExtractBibtexDialog extends BaseDialog<Void> {

@Inject protected StateManager stateManager;
@Inject protected DialogService dialogService;
@Inject protected AiService aiService;
@Inject protected FileUpdateMonitor fileUpdateMonitor;
@Inject protected TaskExecutor taskExecutor;
@Inject protected UndoManager undoManager;
@Inject protected GuiPreferences preferences;

@FXML protected TextArea input;
private final boolean onlineMode;
@FXML protected ButtonType parseButtonType;
@FXML protected ComboBox<OnlinePlainCitationParser> parserChoice;

@FXML private ButtonType parseButtonType;
private final boolean onlineMode;

public ExtractBibtexDialog(boolean onlineMode) {
this.onlineMode = onlineMode;

ViewLoader.view(this)
.load()
.setAsDialogPane(this);

if (onlineMode) {
this.setTitle(Localization.lang("Plain References Parser (online)"));
} else {
Expand All @@ -59,16 +67,25 @@ public ExtractBibtexDialog(boolean onlineMode) {
@FXML
private void initialize() {
BibDatabaseContext database = stateManager.getActiveDatabase().orElseThrow(() -> new NullPointerException("Database null"));

BibtexExtractorViewModel viewModel = new BibtexExtractorViewModel(
onlineMode,
database,
dialogService,
aiService,
preferences,
fileUpdateMonitor,
taskExecutor,
undoManager,
stateManager);

new ViewModelListCellFactory<OnlinePlainCitationParser>()
.withText(OnlinePlainCitationParser::getLocalizedName)
.install(parserChoice);
parserChoice.getItems().setAll(viewModel.onlinePlainCitationParsers());
parserChoice.valueProperty().bindBidirectional(viewModel.parserChoice());
parserChoice.setDisable(!onlineMode);

input.textProperty().bindBidirectional(viewModel.inputTextProperty());
String clipText = ClipBoardManager.getContents();
if (StringUtil.isBlank(clipText)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.ComboBox?>
<fx:root spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jabref.gui.preferences.websearch.WebSearchTab">
Expand All @@ -21,6 +22,10 @@
<CheckBox fx:id="warnAboutDuplicatesOnImport" text="%Warn about duplicates on import"/>
<CheckBox fx:id="downloadLinkedOnlineFiles" text="%Download linked online files"/>
<CheckBox fx:id="keepDownloadUrl" text="%Store url for downloaded file" />
<HBox alignment="BASELINE_LEFT" spacing="10">
<Label text="%Default online plain citation parser"/>
<ComboBox fx:id="defaultOnlinePlainCitationParser" HBox.hgrow="ALWAYS"/>
</HBox>

<Label styleClass="sectionHeader" text="%Custom DOI URI"/>
<HBox alignment="CENTER_LEFT" spacing="10.0">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
Expand All @@ -16,7 +17,9 @@
import org.jabref.gui.preferences.AbstractPreferenceTabView;
import org.jabref.gui.preferences.PreferencesTab;
import org.jabref.gui.slr.StudyCatalogItem;
import org.jabref.gui.util.ViewModelListCellFactory;
import org.jabref.gui.util.ViewModelTableRowFactory;
import org.jabref.logic.importer.fetcher.OnlinePlainCitationParser;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.preferences.FetcherApiKey;

Expand All @@ -30,6 +33,7 @@ public class WebSearchTab extends AbstractPreferenceTabView<WebSearchTabViewMode
@FXML private CheckBox warnAboutDuplicatesOnImport;
@FXML private CheckBox downloadLinkedOnlineFiles;
@FXML private CheckBox keepDownloadUrl;
@FXML private ComboBox<OnlinePlainCitationParser> defaultOnlinePlainCitationParser;

@FXML private CheckBox useCustomDOI;
@FXML private TextField useCustomDOIName;
Expand Down Expand Up @@ -69,6 +73,12 @@ public void initialize() {
downloadLinkedOnlineFiles.selectedProperty().bindBidirectional(viewModel.shouldDownloadLinkedOnlineFiles());
keepDownloadUrl.selectedProperty().bindBidirectional(viewModel.shouldKeepDownloadUrl());

new ViewModelListCellFactory<OnlinePlainCitationParser>()
.withText(OnlinePlainCitationParser::getLocalizedName)
.install(defaultOnlinePlainCitationParser);
defaultOnlinePlainCitationParser.itemsProperty().bind(viewModel.onlinePlainCitationParsers());
defaultOnlinePlainCitationParser.valueProperty().bindBidirectional(viewModel.defaultOnlinePlainCitationParserProperty());

grobidEnabled.selectedProperty().bindBidirectional(viewModel.grobidEnabledProperty());
grobidURL.textProperty().bindBidirectional(viewModel.grobidURLProperty());
grobidURL.disableProperty().bind(grobidEnabled.selectedProperty().not());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.jabref.logic.importer.fetcher.CompositeSearchBasedFetcher;
import org.jabref.logic.importer.fetcher.CustomizableKeyFetcher;
import org.jabref.logic.importer.fetcher.GrobidPreferences;
import org.jabref.logic.importer.fetcher.OnlinePlainCitationParser;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.net.URLDownload;
import org.jabref.logic.os.OS;
Expand All @@ -47,6 +48,8 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty warnAboutDuplicatesOnImportProperty = new SimpleBooleanProperty();
private final BooleanProperty shouldDownloadLinkedOnlineFiles = new SimpleBooleanProperty();
private final BooleanProperty shouldkeepDownloadUrl = new SimpleBooleanProperty();
private final ListProperty<OnlinePlainCitationParser> onlinePlainCitationParsers = new SimpleListProperty<>(FXCollections.observableArrayList(OnlinePlainCitationParser.values()));
private final ObjectProperty<OnlinePlainCitationParser> defaultOnlinePlainCitationParser = new SimpleObjectProperty<>();

private final BooleanProperty useCustomDOIProperty = new SimpleBooleanProperty();
private final StringProperty useCustomDOINameProperty = new SimpleStringProperty("");
Expand Down Expand Up @@ -85,6 +88,8 @@ public void setValues() {
warnAboutDuplicatesOnImportProperty.setValue(importerPreferences.shouldWarnAboutDuplicatesOnImport());
shouldDownloadLinkedOnlineFiles.setValue(filePreferences.shouldDownloadLinkedFiles());
shouldkeepDownloadUrl.setValue(filePreferences.shouldKeepDownloadUrl());
defaultOnlinePlainCitationParser.setValue(importerPreferences.getDefaultOnlinePlainCitationParser());

useCustomDOIProperty.setValue(doiPreferences.isUseCustom());
useCustomDOINameProperty.setValue(doiPreferences.getDefaultBaseURI());

Expand Down Expand Up @@ -112,6 +117,7 @@ public void storeSettings() {
importerPreferences.setWarnAboutDuplicatesOnImport(warnAboutDuplicatesOnImportProperty.getValue());
filePreferences.setDownloadLinkedFiles(shouldDownloadLinkedOnlineFiles.getValue());
filePreferences.setKeepDownloadUrl(shouldkeepDownloadUrl.getValue());
importerPreferences.setDefaultOnlinePlainCitationParser(defaultOnlinePlainCitationParser.getValue());
grobidPreferences.setGrobidEnabled(grobidEnabledProperty.getValue());
grobidPreferences.setGrobidOptOut(grobidPreferences.isGrobidOptOut());
grobidPreferences.setGrobidURL(grobidURLProperty.getValue());
Expand All @@ -137,6 +143,14 @@ public BooleanProperty generateKeyOnImportProperty() {
return generateKeyOnImportProperty;
}

public ListProperty<OnlinePlainCitationParser> onlinePlainCitationParsers() {
return onlinePlainCitationParsers;
}

public ObjectProperty<OnlinePlainCitationParser> defaultOnlinePlainCitationParserProperty() {
return defaultOnlinePlainCitationParser;
}

public BooleanProperty useCustomDOIProperty() {
return this.useCustomDOIProperty;
}
Expand Down
21 changes: 19 additions & 2 deletions src/main/java/org/jabref/logic/importer/ImporterPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;

import org.jabref.logic.importer.fetcher.OnlinePlainCitationParser;
import org.jabref.logic.importer.fileformat.CustomImporter;
import org.jabref.logic.preferences.FetcherApiKey;

public class ImporterPreferences {

private final BooleanProperty importerEnabled;
private final BooleanProperty generateNewKeyOnImport;
private final BooleanProperty warnAboutDuplicatesOnImport;
Expand All @@ -26,14 +26,18 @@ public class ImporterPreferences {
private final ObservableSet<CustomImporter> customImporters;
private final BooleanProperty persistCustomKeys;
private final ObservableList<String> catalogs;
private final ObjectProperty<OnlinePlainCitationParser> defaultOnlinePlainCitationParser;

public ImporterPreferences(boolean importerEnabled,
boolean generateNewKeyOnImport,
Path importWorkingDirectory,
boolean warnAboutDuplicatesOnImport,
Set<CustomImporter> customImporters,
Set<FetcherApiKey> apiKeys,
boolean persistCustomKeys,
List<String> catalogs) {
List<String> catalogs,
OnlinePlainCitationParser defaultOnlinePlainCitationParser
) {
this.importerEnabled = new SimpleBooleanProperty(importerEnabled);
this.generateNewKeyOnImport = new SimpleBooleanProperty(generateNewKeyOnImport);
this.importWorkingDirectory = new SimpleObjectProperty<>(importWorkingDirectory);
Expand All @@ -42,6 +46,7 @@ public ImporterPreferences(boolean importerEnabled,
this.apiKeys = FXCollections.observableSet(apiKeys);
this.persistCustomKeys = new SimpleBooleanProperty(persistCustomKeys);
this.catalogs = FXCollections.observableArrayList(catalogs);
this.defaultOnlinePlainCitationParser = new SimpleObjectProperty<>(defaultOnlinePlainCitationParser);
}

public boolean areImporterEnabled() {
Expand Down Expand Up @@ -133,4 +138,16 @@ public void setCatalogs(List<String> catalogs) {
public ObservableList<String> getCatalogs() {
return catalogs;
}

public OnlinePlainCitationParser getDefaultOnlinePlainCitationParser() {
return defaultOnlinePlainCitationParser.get();
}

public ObjectProperty<OnlinePlainCitationParser> defaultOnlinePlainCitationParserProperty() {
return defaultOnlinePlainCitationParser;
}

public void setDefaultOnlinePlainCitationParser(OnlinePlainCitationParser defaultOnlinePlainCitationParser) {
this.defaultOnlinePlainCitationParser.set(defaultOnlinePlainCitationParser);
}
}
Loading

0 comments on commit 7d0c04f

Please sign in to comment.