From 7e10dd3cfdb992da2d24d17e7ff965d2d51c9c61 Mon Sep 17 00:00:00 2001 From: PhilKes Date: Sat, 25 May 2024 13:51:16 +0200 Subject: [PATCH] feat: optional apiKey field for Ollama service --- .../completions/CompletionClientProvider.java | 11 ++++++--- .../form/LlamaServerPreferencesForm.java | 2 +- .../codegpt/credentials/CredentialsStore.kt | 3 ++- .../service/ollama/OllamaSettingsForm.kt | 24 +++++++++++++++++++ .../resources/messages/codegpt.properties | 2 +- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java index 6f4ce8a9..b4f8327f 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java @@ -104,9 +104,14 @@ public class CompletionClientProvider { .getService(OllamaSettings.class) .getState() .getHost(); - return new OllamaClient.Builder() - .setHost(host) - .build(getDefaultClientBuilder()); + var builder = new OllamaClient.Builder() + .setHost(host); + + String apiKey = getCredential(CredentialKey.OLLAMA_API_KEY); + if (apiKey != null && !apiKey.isBlank()) { + builder.setApiKey(apiKey); + } + return builder.build(getDefaultClientBuilder()); } diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/llama/form/LlamaServerPreferencesForm.java b/src/main/java/ee/carlrobert/codegpt/settings/service/llama/form/LlamaServerPreferencesForm.java index 907aad19..6efa4ecc 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/service/llama/form/LlamaServerPreferencesForm.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/llama/form/LlamaServerPreferencesForm.java @@ -148,7 +148,7 @@ public class LlamaServerPreferencesForm { .withLabel(CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label")) .resizeX(false) .withComment( - CodeGPTBundle.get("settingsConfigurable.service.llama.apiKey.comment")) + CodeGPTBundle.get("settingsConfigurable.shared.apiKey.comment")) .withCommentHyperlinkListener(UIUtil::handleHyperlinkClicked) .createPanel(); return withEmptyLeftBorder(FormBuilder.createFormBuilder() diff --git a/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt b/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt index f5fcad55..10c4cca4 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt @@ -42,6 +42,7 @@ object CredentialsStore { AZURE_ACTIVE_DIRECTORY_TOKEN, YOU_ACCOUNT_PASSWORD, LLAMA_API_KEY, - GOOGLE_API_KEY + GOOGLE_API_KEY, + OLLAMA_API_KEY, } } \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ollama/OllamaSettingsForm.kt b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ollama/OllamaSettingsForm.kt index 8206362f..f1e63f0e 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ollama/OllamaSettingsForm.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/settings/service/ollama/OllamaSettingsForm.kt @@ -7,9 +7,13 @@ import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.observable.util.whenTextChangedFromUi import com.intellij.openapi.ui.ComboBox import com.intellij.ui.TitledSeparator +import com.intellij.ui.components.JBPasswordField import com.intellij.ui.components.JBTextField import com.intellij.util.ui.FormBuilder import ee.carlrobert.codegpt.CodeGPTBundle +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.OLLAMA_API_KEY +import ee.carlrobert.codegpt.credentials.CredentialsStore.getCredential +import ee.carlrobert.codegpt.credentials.CredentialsStore.setCredential import ee.carlrobert.codegpt.settings.service.CodeCompletionConfigurationForm import ee.carlrobert.codegpt.ui.OverlayUtil import ee.carlrobert.codegpt.ui.UIUtil @@ -31,6 +35,7 @@ class OllamaSettingsForm { private val hostField: JBTextField private val modelComboBox: ComboBox private val codeCompletionConfigurationForm: CodeCompletionConfigurationForm + private val apiKeyField: JBPasswordField companion object { private val logger = thisLogger() @@ -55,6 +60,12 @@ class OllamaSettingsForm { } } refreshModelsButton.addActionListener { refreshModels() } + apiKeyField = JBPasswordField().apply { + columns = 30 + text = runBlocking(Dispatchers.IO) { + getCredential(OLLAMA_API_KEY) + } + } } fun getForm(): JPanel = FormBuilder.createFormBuilder() @@ -73,6 +84,13 @@ class OllamaSettingsForm { add(refreshModelsButton, BorderLayout.EAST) } ) + .addComponent(TitledSeparator(CodeGPTBundle.get("settingsConfigurable.shared.authentication.title"))) + .setFormLeftIndent(32) + .addLabeledComponent( + CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label"), + apiKeyField + ) + .addComponentToRightColumn(UIUtil.createComment("settingsConfigurable.shared.apiKey.comment")) .panel ) .addComponent(TitledSeparator(CodeGPTBundle.get("shared.codeCompletions"))) @@ -88,6 +106,8 @@ class OllamaSettingsForm { } } + fun getApiKey(): String? = String(apiKeyField.password).ifEmpty { null } + fun resetForm() { service().state.run { hostField.text = host @@ -95,6 +115,7 @@ class OllamaSettingsForm { codeCompletionConfigurationForm.isCodeCompletionsEnabled = codeCompletionsEnabled codeCompletionConfigurationForm.fimTemplate = fimTemplate } + apiKeyField.text = getCredential(OLLAMA_API_KEY) } fun applyChanges() { @@ -104,6 +125,7 @@ class OllamaSettingsForm { codeCompletionsEnabled = codeCompletionConfigurationForm.isCodeCompletionsEnabled fimTemplate = codeCompletionConfigurationForm.fimTemplate!! } + setCredential(OLLAMA_API_KEY, getApiKey()) } fun isModified() = service().state.run { @@ -111,6 +133,7 @@ class OllamaSettingsForm { || modelComboBox.item != model || codeCompletionConfigurationForm.isCodeCompletionsEnabled != codeCompletionsEnabled || codeCompletionConfigurationForm.fimTemplate != fimTemplate + || getApiKey() != getCredential(OLLAMA_API_KEY) } private fun refreshModels() { @@ -119,6 +142,7 @@ class OllamaSettingsForm { val models = runBlocking(Dispatchers.IO) { OllamaClient.Builder() .setHost(hostField.text) + .setApiKey(getApiKey()) .build() .modelTags .models diff --git a/src/main/resources/messages/codegpt.properties b/src/main/resources/messages/codegpt.properties index 576d71e3..4acbc154 100644 --- a/src/main/resources/messages/codegpt.properties +++ b/src/main/resources/messages/codegpt.properties @@ -58,7 +58,6 @@ settingsConfigurable.service.you.displayResults.label=Display web search results settingsConfigurable.service.you.authentication.title=Authentication (Optional) settingsConfigurable.service.you.userInformation.title=User Information settingsConfigurable.service.you.chatPreferences.title=Chat Preferences -settingsConfigurable.service.llama.apiKey.comment=API Key for authentication, added to 'Authorization' header as bearer (Optional) settingsConfigurable.service.llama.modelPreferences.title=Model Preferences settingsConfigurable.service.llama.serverPreferences.title=Server Preferences settingsConfigurable.service.llama.modelSize.label=Model size: @@ -99,6 +98,7 @@ settingsConfigurable.service.llama.overlay.modelNotDownloaded.text=Model is not settingsConfigurable.shared.authentication.title=Authentication settingsConfigurable.shared.requestConfiguration.title=Request Configuration settingsConfigurable.shared.apiKey.label=API key: +settingsConfigurable.shared.apiKey.comment=API Key for authentication, added to 'Authorization' header as bearer (Optional) settingsConfigurable.shared.baseHost.label=Base host: settingsConfigurable.shared.path.label=Path: settingsConfigurable.shared.model.label=Model: