InAnYan / jabref

Graphical Java application for managing BibTeX and biblatex (.bib) databases
https://devdocs.jabref.org
MIT License
0 stars 0 forks source link

API token should be fetched later #104

Closed koppor closed 2 months ago

koppor commented 2 months ago

JabRef uses Java Key Ring to connect to password stores.

org.jabref.preferences.JabRefPreferences#getAiPreferences access that key store when creating the AI Chat tab. This leads to following startup error output:

2024-08-04 10:50:20 [JavaFX Application Thread] org.jabref.preferences.JabRefPreferences.getAiApiTokenFromKeyring()
WARN: JabRef could not open keyring for retrieving OpenAI API token: com.github.javakeyring.PasswordAccessException: Error code 1168
        at java.keyring@1.0.4/com.github.javakeyring.internal.windows.WinCredentialStoreBackend.getPassword(WinCredentialStoreBackend.java:61)
        at java.keyring@1.0.4/com.github.javakeyring.Keyring.getPassword(Keyring.java:90)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getAiApiTokenFromKeyring(JabRefPreferences.java:2808)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getAiPreferences(JabRefPreferences.java:2773)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.initialize(JabRefGUI.java:159)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.start(JabRefGUI.java:90)
        at javafx.graphics@22.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
        at javafx.graphics@22.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at javafx.graphics@22.0.2/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics@22.0.2/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
        at java.base/java.lang.Thread.run(Thread.java:1583)
2024-08-04 10:50:21 [JavaFX Application Thread] org.jabref.gui.StateManager.setActiveDatabase()

When opening preferences, the key is there.


When using Gnome, on startup, one will be asked to open the key store. This is not necessary. It is necessary when interacting with the AI.

Please postpone the call to org.jabref.preferences.JabRefPreferences#getAiApiTokenFromKeyring to the latest point in time (and store the key internally once retrieved). (OK, one also has to take care if they key is changed by the user)

InAnYan commented 2 months ago

I'm not sure how to code this properly. This will probably break some symmetry and used practice, but yes, the issue is right.

Can I make org.jabref.preferences.JabRefPreferences#getAiPreferences public?

koppor commented 2 months ago

I'm not sure how to code this properly. This will probably break some symmetry and used practice, but yes, the issue is right.

Maybe, the other places need to be changed "accordingly" (e.g., proxy password, ...). I think, however, that it is OK for JabRef users with proxy passwords that JabRef asks for the password right at the start. For API keys, I am not that sure...

With your changes, an example can be shown how it will work.

Can I make org.jabref.preferences.JabRefPreferences#getAiPreferences public?

Yes. This will lead to another method signature in PreferenceServcid, whcih is OK.

koppor commented 2 months ago

Maybe "Future" helps?

InAnYan commented 2 months ago

Okay, I think I managed to do this in a recent push

koppor commented 2 months ago

No, see output of gradlew run:

$ ./gradlew run

> Configure project :
Project : => 'org.jabref' Java module

> Task :run
WARNING: Using incubator modules: jdk.incubator.vector
Messages are not initialized before accessing key: Display help on command line options
2024-08-06 17:00:16 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.addStylesheetToWatchlist()
INFO: Watching css C:\git-repositories\jabref-all\jabref\build\resources\main\org\jabref\gui\Base.css for live updates
2024-08-06 17:00:16 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.updateThemeSettings()
INFO: Not updating theme because it hasn't changed
2024-08-06 17:00:16 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.updateThemeSettings()
INFO: Theme set to Theme{type=DEFAULT, name=''} with base css StyleSheet{file:/C:/git-repositories/jabref-all/jabref/build/resources/main/org/jabref/gui/Base.css}
2024-08-06 17:00:16 [JavaFX Application Thread] org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider()
WARN: JabRef could not open keyring for retrieving OpenAI API token: com.github.javakeyring.PasswordAccessException: Error code 1168
        at java.keyring@1.0.4/com.github.javakeyring.internal.windows.WinCredentialStoreBackend.getPassword(WinCredentialStoreBackend.java:61)
        at java.keyring@1.0.4/com.github.javakeyring.Keyring.getPassword(Keyring.java:90)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider(JabRefPreferences.java:2855)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getAiPreferences(JabRefPreferences.java:2795)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.initialize(JabRefGUI.java:159)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.start(JabRefGUI.java:90)
        at javafx.graphics@22.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
        at javafx.graphics@22.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at javafx.graphics@22.0.2/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics@22.0.2/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
        at java.base/java.lang.Thread.run(Thread.java:1583)
2024-08-06 17:00:16 [pool-2-thread-1] org.jabref.logic.ai.models.EmbeddingModel.rebuild()
INFO: Downloading embedding model...
Loading:     100% |========================================|
2024-08-06 17:00:16 [pool-2-thread-1] ai.djl.pytorch.jni.LibUtils.downloadPyTorch()
WARN: No matching cuda flavor for win-x86_64 found: cu065.
2024-08-06 17:00:17 [pool-2-thread-1] ai.djl.pytorch.engine.PtEngine.newInstance()
INFO: PyTorch graph executor optimizer is enabled, this may impact your inference latency and throughput. See: https://docs.djl.ai/docs/development/inference_performance_optimization.html#graph-executor-optimization
2024-08-06 17:00:17 [pool-2-thread-1] ai.djl.pytorch.engine.PtEngine.newInstance()
INFO: Number of inter-op threads is 24
2024-08-06 17:00:17 [pool-2-thread-1] ai.djl.pytorch.engine.PtEngine.newInstance()
INFO: Number of intra-op threads is 12
2024-08-06 17:00:17 [pool-2-thread-1] ai.djl.util.Platform.detectPlatform()
INFO: Found matching platform from: jar:file:///C:/Users/koppor/.gradle/caches/modules-2/files-2.1/ai.djl.huggingface/tokenizers/0.29.0/edd38326d16523f2b8c2b1e360b896e7ae48a1fa/tokenizers-0.29.0.jar!/native/lib/tokenizers.properties
2024-08-06 17:00:17 [JavaFX Application Thread] org.jabref.gui.StateManager.setActiveDatabase()
INFO: No open database detected
2024-08-06 17:00:18 [pool-2-thread-2] org.jabref.gui.JabRefDialogService.notify()
INFO: Opening: 'C:\Users\koppor\OneDrive\Projects\JabRef-AI\Chocolate.bib'
2024-08-06 17:00:18 [JavaFX Application Thread] sun.util.logging.internal.LoggingProviderImpl$JULWrapper.log()
WARN: Resource "" not found.
2024-08-06 17:00:19 [JavaFX Application Thread] sun.util.logging.internal.LoggingProviderImpl$JULWrapper.log()
WARN: Resource "" not found.
2024-08-06 17:00:19 [JavaFX Application Thread] org.jabref.logic.ai.models.EmbeddingModel.lambda$startRebuildingTask$0()
INFO: Embedding model was successfully downloaded
2024-08-06 17:00:19 [JavaFX Application Thread] org.apache.lucene.internal.vectorization.PanamaVectorizationProvider.<init>()
INFO: Java vector incubator API enabled; uses preferredBitSize=256; FMA enabled
InAnYan commented 2 months ago

Are you sure you started JabRef without AI-enabled?

koppor commented 2 months ago

I highlight important terms of my issue description:

image

I try TL;DR:

koppor commented 2 months ago

If this is too difficult to implement, we can postpone to the famous week 12.

InAnYan commented 2 months ago

Ah, I see. I just implemented it for:

  1. User opens preferences
  2. Agrees to AI
  3. Saves preferences

And after that the key will be fetched

InAnYan commented 2 months ago

As I understand, we should fetch the key ONLY when we start chatting or summarizing?

koppor commented 2 months ago

As I understand, we should fetch the key ONLY when we start chatting or summarizing?

Yes.


For the preferences, it is difficult. A "perfect" solution would be follwowing:

Assumption: Password field is write-only

There is no (!) eye icon - thus I cannot read from the field:

grafik

As a consequence, the field is write only.

Question: Should the user know if (s)he entered anything?

After the user changed the text field, the new key is stored in the key store.

No need to read the api key ever in the preferences.

koppor commented 2 months ago

Note that there is something reading the the AI Preferences - and thus the key:

> Task :run
WARNING: Using incubator modules: jdk.incubator.vector
Messages are not initialized before accessing key: Display help on command line options
2024-08-07 06:27:15 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.addStylesheetToWatchlist()
INFO: Watching css /home/vagrant/jabref/build/resources/main/org/jabref/gui/Base.css for live updates
2024-08-07 06:27:15 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.updateThemeSettings()
INFO: Not updating theme because it hasn't changed
2024-08-07 06:27:15 [JavaFX Application Thread] org.jabref.gui.theme.ThemeManager.updateThemeSettings()
INFO: Theme set to Theme{type=DEFAULT, name=''} with base css StyleSheet{file:/home/vagrant/jabref/build/resources/main/org/jabref/gui/Base.css}
2024-08-07 06:27:15 [JavaFX Application Thread] org.freedesktop.dbus.connections.transports.TransportBuilder.build()
INFO: Using transport dbus-java-transport-native-unixsocket to connect to unix:path=/run/user/1000/bus
2024-08-07 06:27:16 [JavaFX Application Thread] org.freedesktop.secret.handlers.SignalHandler.await()
INFO: Await signal Prompt.Completed(/org/freedesktop/secrets/prompt/u1) within 120 seconds.
2024-08-07 06:27:20 [DBus-Signal-Receiver-1] org.freedesktop.secret.handlers.SignalHandler.handle()
INFO: Received signal Service.CollectionChanged: /org/freedesktop/secrets/collection/login
2024-08-07 06:27:20 [DBus-Signal-Receiver-1] org.freedesktop.secret.handlers.SignalHandler.handle()
INFO: Received signal Prompt.Completed(/org/freedesktop/secrets/prompt/u1): {dismissed: false, result: [[/org/freedesktop/secrets/aliases/default]]}
2024-08-07 06:27:20 [JavaFX Application Thread] org.freedesktop.dbus.connections.transports.TransportBuilder.build()
INFO: Using transport dbus-java-transport-native-unixsocket to connect to unix:path=/run/user/1000/bus
2024-08-07 06:27:20 [JavaFX Application Thread] org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider()
WARN: JabRef could not open keyring for retrieving OpenAI API token: com.github.javakeyring.PasswordAccessException: No stored credentials match org.jabref.ai account: apitoken-MISTRAL_AI
        at java.keyring@1.0.4/com.github.javakeyring.internal.freedesktop.FreedesktopKeyringBackend.throwNoExistingCredentialException(FreedesktopKeyringBackend.java:161)
        at java.keyring@1.0.4/com.github.javakeyring.internal.freedesktop.FreedesktopKeyringBackend.getPassword(FreedesktopKeyringBackend.java:91)
        at java.keyring@1.0.4/com.github.javakeyring.Keyring.getPassword(Keyring.java:90)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider(JabRefPreferences.java:2855)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getAiPreferences(JabRefPreferences.java:2794)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.initialize(JabRefGUI.java:159)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.start(JabRefGUI.java:90)
        at javafx.graphics@22.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
        at javafx.graphics@22.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at javafx.graphics@22.0.2/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
        at javafx.graphics@22.0.2/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$10(GtkApplication.java:264)
        at java.base/java.lang.Thread.run(Thread.java:1583)
2024-08-07 06:27:20 [JavaFX Application Thread] org.freedesktop.dbus.connections.transports.TransportBuilder.build()
INFO: Using transport dbus-java-transport-native-unixsocket to connect to unix:path=/run/user/1000/bus
2024-08-07 06:27:20 [JavaFX Application Thread] org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider()
WARN: JabRef could not open keyring for retrieving OpenAI API token: com.github.javakeyring.PasswordAccessException: No stored credentials match org.jabref.ai account: apitoken-HUGGING_FACE
        at java.keyring@1.0.4/com.github.javakeyring.internal.freedesktop.FreedesktopKeyringBackend.throwNoExistingCredentialException(FreedesktopKeyringBackend.java:161)
        at java.keyring@1.0.4/com.github.javakeyring.internal.freedesktop.FreedesktopKeyringBackend.getPassword(FreedesktopKeyringBackend.java:91)
        at java.keyring@1.0.4/com.github.javakeyring.Keyring.getPassword(Keyring.java:90)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getApiKeyForAiProvider(JabRefPreferences.java:2855)
        at org.jabref@100.0.0/org.jabref.preferences.JabRefPreferences.getAiPreferences(JabRefPreferences.java:2795)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.initialize(JabRefGUI.java:159)
        at org.jabref@100.0.0/org.jabref.gui.JabRefGUI.start(JabRefGUI.java:90)
        at javafx.graphics@22.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:839)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:483)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
        at javafx.graphics@22.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
        at javafx.graphics@22.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
        at javafx.graphics@22.0.2/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
        at javafx.graphics@22.0.2/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$10(GtkApplication.java:264)
        at java.base/java.lang.Thread.run(Thread.java:1583)
2024-08-07 06:27:21 [pool-2-thread-1] org.jabref.logic.ai.models.EmbeddingModel.rebuild()
koppor commented 2 months ago

See my comment https://github.com/JabRef/jabref/commit/1d4c383ddc31c4d2423949da51f288b5a81e4901 on a possible code-based solution.

InAnYan commented 2 months ago

Hope I managed to do this in a recent push

koppor commented 2 months ago

I commented at https://github.com/JabRef/jabref/pull/11430#pullrequestreview-2225753481 - please refine the code.

InAnYan commented 2 months ago

I took this approach: I mark unloaded keys as empty strings. If the string is empty, then it will be retrieved from keyring. I think, this is okay?

(You should see a message "InAnYan referenced this issue", above this comment)

About factoring out fields: I wonder, if it's really needed. Currently I only see one purpose - grouping. If it had more complex logic..

InAnYan commented 2 months ago

Actually, I understood. It would be better to have a separate class for API keys in case there will be more of them. They should be stored in a Map<AiProvider, String>, or something like that

koppor commented 2 months ago

Actually, I understood. It would be better to have a separate class for API keys in case there will be more of them.

Yes!

They should be stored in a Map<AiProvider, String>, or something like that

Yes. The enum org.jabref.preferences.ai.AiProvider is really good.

The label can directly be used as last part of the item name in the java key store.

InAnYan commented 2 months ago

I wonder, Oliver, if we can make a separate issue for "Refactor support of multiple AI providers", because not only API key is associated with an AI provider.

For now we have a simple fix.

What if I make that issue and close this one (close this - because API token is fetched later)

koppor commented 2 months ago

Go ahead with creating a new issue and closing this (with a reference to the new isssue)

koppor commented 2 months ago

There still was a call to rebuild reading the API key in org.jabref.logic.ai.models.JabRefChatLanguageModel#JabRefChatLanguageModel. Removed at 400d83e7e82e1b716ccb3b16f64aa9bb.