From 4653ba47050944ed7c292439fd3d9303918e04fa Mon Sep 17 00:00:00 2001 From: Stephan Janssen Date: Thu, 12 Dec 2024 19:54:02 +0100 Subject: [PATCH] Fix #384: Tavily and Google Search fixed --- .../service/DevoxxGenieSettingsService.java | 4 +- .../service/NonStreamingPromptExecutor.java | 5 +- .../service/websearch/WebSearchExecutor.java | 2 + .../service/websearch/WebSearchService.java | 36 ++++---- .../genie/ui/panel/SearchOptionsPanel.java | 2 +- .../ui/settings/DevoxxGenieStateService.java | 8 +- .../llm/LLMProvidersConfigurable.java | 88 +++++++++---------- .../WebSearchProvidersComponent.java | 57 +++++++++--- .../WebSearchProvidersConfigurable.java | 22 +++-- .../genie/util/ChatMessageContextUtil.java | 29 +++--- src/main/resources/META-INF/plugin.xml | 1 + .../service/PromptExecutionServiceIT.java | 2 +- 12 files changed, 159 insertions(+), 97 deletions(-) diff --git a/core/src/main/java/com/devoxx/genie/service/DevoxxGenieSettingsService.java b/core/src/main/java/com/devoxx/genie/service/DevoxxGenieSettingsService.java index 44c47eb7..cf0b57f5 100644 --- a/core/src/main/java/com/devoxx/genie/service/DevoxxGenieSettingsService.java +++ b/core/src/main/java/com/devoxx/genie/service/DevoxxGenieSettingsService.java @@ -44,7 +44,7 @@ public interface DevoxxGenieSettingsService { String getOpenRouterKey(); - Boolean getEnableWebSearch(); + Boolean getIsWebSearchEnabled(); String getGoogleSearchKey(); @@ -128,7 +128,7 @@ public interface DevoxxGenieSettingsService { void setOpenRouterKey(String key); - void setEnableWebSearch(Boolean flag); + void setIsWebSearchEnabled(Boolean flag); void setGoogleSearchKey(String key); diff --git a/src/main/java/com/devoxx/genie/service/NonStreamingPromptExecutor.java b/src/main/java/com/devoxx/genie/service/NonStreamingPromptExecutor.java index 645505a6..40adf126 100644 --- a/src/main/java/com/devoxx/genie/service/NonStreamingPromptExecutor.java +++ b/src/main/java/com/devoxx/genie/service/NonStreamingPromptExecutor.java @@ -46,7 +46,7 @@ public void execute(ChatMessageContext chatMessageContext, isCancelled = false; if (FIND_COMMAND.equals(chatMessageContext.getCommandName())) { - semanticSearch(chatMessageContext, promptOutputPanel, enableButtons); + semanticSearch(chatMessageContext, promptOutputPanel); enableButtons.run(); return; } @@ -101,8 +101,7 @@ private void prompt(ChatMessageContext chatMessageContext, * @param promptOutputPanel the prompt output panel */ private static void semanticSearch(ChatMessageContext chatMessageContext, - @NotNull PromptOutputPanel promptOutputPanel, - Runnable enableButtons) { + @NotNull PromptOutputPanel promptOutputPanel) { try { SemanticSearchService semanticSearchService = SemanticSearchService.getInstance(); Map searchResults = semanticSearchService.search( diff --git a/src/main/java/com/devoxx/genie/service/websearch/WebSearchExecutor.java b/src/main/java/com/devoxx/genie/service/websearch/WebSearchExecutor.java index 54852f0b..cde09689 100644 --- a/src/main/java/com/devoxx/genie/service/websearch/WebSearchExecutor.java +++ b/src/main/java/com/devoxx/genie/service/websearch/WebSearchExecutor.java @@ -13,9 +13,11 @@ public void execute(ChatMessageContext chatMessageContext, @NotNull PromptOutputPanel promptOutputPanel, Runnable enableButtons) { promptOutputPanel.addUserPrompt(chatMessageContext); + long startTime = System.currentTimeMillis(); WebSearchService.getInstance().searchWeb(chatMessageContext) .ifPresent(aiMessage -> { chatMessageContext.setAiMessage(aiMessage); + chatMessageContext.setExecutionTimeMs(System.currentTimeMillis() - startTime); promptOutputPanel.addChatResponse(chatMessageContext); enableButtons.run(); }); diff --git a/src/main/java/com/devoxx/genie/service/websearch/WebSearchService.java b/src/main/java/com/devoxx/genie/service/websearch/WebSearchService.java index 9dc2df86..26c5cc07 100644 --- a/src/main/java/com/devoxx/genie/service/websearch/WebSearchService.java +++ b/src/main/java/com/devoxx/genie/service/websearch/WebSearchService.java @@ -1,9 +1,9 @@ package com.devoxx.genie.service.websearch; import com.devoxx.genie.model.request.ChatMessageContext; -import com.devoxx.genie.service.DevoxxGenieSettingsService; import com.devoxx.genie.ui.settings.DevoxxGenieStateService; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import dev.langchain4j.data.message.AiMessage; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.content.retriever.WebSearchContentRetriever; @@ -17,11 +17,10 @@ import java.util.Optional; -import static com.devoxx.genie.model.Constant.GOOGLE_SEARCH_ACTION; -import static com.devoxx.genie.model.Constant.TAVILY_SEARCH_ACTION; - public class WebSearchService { + private static final Logger LOG = Logger.getInstance(WebSearchService.class); + public static WebSearchService getInstance() { return ApplicationManager.getApplication().getService(WebSearchService.class); } @@ -41,7 +40,10 @@ interface SearchWebsite { * @return the AI message */ public @NotNull Optional searchWeb(@NotNull ChatMessageContext chatMessageContext) { - WebSearchEngine engine = createWebSearchEngine(chatMessageContext.getContext()); + LOG.debug("Searching the web for: " + chatMessageContext.getUserPrompt()); + + WebSearchEngine engine = createWebSearchEngine(); + return Optional.ofNullable(engine) .flatMap(webSearchEngine -> executeSearchCommand(webSearchEngine, chatMessageContext)); } @@ -55,6 +57,8 @@ interface SearchWebsite { */ private @NotNull Optional executeSearchCommand(WebSearchEngine webSearchEngine, @NotNull ChatMessageContext chatMessageContext) { + LOG.debug("Executing search command for: " + chatMessageContext.getUserPrompt()); + ContentRetriever contentRetriever = WebSearchContentRetriever.builder() .webSearchEngine(webSearchEngine) .maxResults(DevoxxGenieStateService.getInstance().getMaxSearchResults()) @@ -70,25 +74,25 @@ interface SearchWebsite { /** * Get the web search engine. - * - * @param searchType the search type * @return the web search engine */ - private @Nullable WebSearchEngine createWebSearchEngine(@NotNull String searchType) { - DevoxxGenieSettingsService settings = DevoxxGenieStateService.getInstance(); + private @Nullable WebSearchEngine createWebSearchEngine() { + LOG.debug("Creating web search engine"); + DevoxxGenieStateService stateService = DevoxxGenieStateService.getInstance(); - if (searchType.equals(TAVILY_SEARCH_ACTION) && settings.getTavilySearchKey() != null) { + if (stateService.isTavilySearchEnabled()) { return TavilyWebSearchEngine.builder() - .apiKey(settings.getTavilySearchKey()) + .apiKey(stateService.getTavilySearchKey()) .build(); - } else if (searchType.equals(GOOGLE_SEARCH_ACTION) && - settings.getGoogleSearchKey() != null && - settings.getGoogleCSIKey() != null) { + } else if (stateService.isGoogleSearchEnabled() && + stateService.getGoogleSearchKey() != null && + stateService.getGoogleCSIKey() != null) { return GoogleCustomWebSearchEngine.builder() - .apiKey(settings.getGoogleSearchKey()) - .csi(settings.getGoogleCSIKey()) + .apiKey(stateService.getGoogleSearchKey()) + .csi(stateService.getGoogleCSIKey()) .build(); } + LOG.info("Web search engine not found or all disabled"); return null; } } diff --git a/src/main/java/com/devoxx/genie/ui/panel/SearchOptionsPanel.java b/src/main/java/com/devoxx/genie/ui/panel/SearchOptionsPanel.java index e0867a37..0bfcf7cc 100644 --- a/src/main/java/com/devoxx/genie/ui/panel/SearchOptionsPanel.java +++ b/src/main/java/com/devoxx/genie/ui/panel/SearchOptionsPanel.java @@ -134,7 +134,7 @@ private void updateInitialVisibility(@NotNull DevoxxGenieStateService stateServi // Set initial visibility based on state service switches.get(0).setVisible(stateService.getRagEnabled()); switches.get(1).setVisible(stateService.getGitDiffEnabled()); - switches.get(2).setVisible(stateService.getEnableWebSearch()); + switches.get(2).setVisible(stateService.getIsWebSearchEnabled()); // Update panel visibility updatePanelVisibility(); diff --git a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java index 6394376f..f7ceb651 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java +++ b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java @@ -69,7 +69,7 @@ public static DevoxxGenieStateService getInstance() { private String jlamaUrl = JLAMA_MODEL_URL; private String customOpenAIUrl = ""; - // + // Local LLM Providers private boolean isOllamaEnabled = true; private boolean isLmStudioEnabled = true; private boolean isGpt4AllEnabled = true; @@ -79,6 +79,7 @@ public static DevoxxGenieStateService getInstance() { private boolean isJlamaEnabled = true; private boolean isCustomOpenAIEnabled = false; + // Remote LLM Providers private boolean isOpenAIEnabled = false; private boolean isMistralEnabled = false; private boolean isAnthropicEnabled = false; @@ -103,7 +104,10 @@ public static DevoxxGenieStateService getInstance() { private String azureOpenAIKey = ""; // Search API Keys - private Boolean enableWebSearch = ENABLE_WEB_SEARCH; + private Boolean isWebSearchEnabled = ENABLE_WEB_SEARCH; + + private boolean tavilySearchEnabled = false; + private boolean googleSearchEnabled = false; private String googleSearchKey = ""; private String googleCSIKey = ""; diff --git a/src/main/java/com/devoxx/genie/ui/settings/llm/LLMProvidersConfigurable.java b/src/main/java/com/devoxx/genie/ui/settings/llm/LLMProvidersConfigurable.java index 5092bb16..6de089f4 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/llm/LLMProvidersConfigurable.java +++ b/src/main/java/com/devoxx/genie/ui/settings/llm/LLMProvidersConfigurable.java @@ -48,53 +48,53 @@ public JComponent createComponent() { */ @Override public boolean isModified() { - DevoxxGenieStateService settings = DevoxxGenieStateService.getInstance(); + DevoxxGenieStateService stateService = DevoxxGenieStateService.getInstance(); boolean isModified = false; - isModified |= !settings.getStreamMode().equals(llmSettingsComponent.getStreamModeCheckBox().isSelected()); - - isModified |= isFieldModified(llmSettingsComponent.getOpenAIKeyField(), settings.getOpenAIKey()); - isModified |= isFieldModified(llmSettingsComponent.getMistralApiKeyField(), settings.getMistralKey()); - isModified |= isFieldModified(llmSettingsComponent.getAnthropicApiKeyField(), settings.getAnthropicKey()); - isModified |= isFieldModified(llmSettingsComponent.getGroqApiKeyField(), settings.getGroqKey()); - isModified |= isFieldModified(llmSettingsComponent.getDeepInfraApiKeyField(), settings.getDeepInfraKey()); - isModified |= isFieldModified(llmSettingsComponent.getGeminiApiKeyField(), settings.getGeminiKey()); - isModified |= isFieldModified(llmSettingsComponent.getDeepSeekApiKeyField(), settings.getDeepSeekKey()); - isModified |= isFieldModified(llmSettingsComponent.getLlamaCPPModelUrlField(), settings.getLlamaCPPUrl()); - isModified |= isFieldModified(llmSettingsComponent.getJlamaModelUrlField(), settings.getJlamaUrl()); - isModified |= isFieldModified(llmSettingsComponent.getOpenRouterApiKeyField(), settings.getOpenRouterKey()); - - isModified |= isFieldModified(llmSettingsComponent.getOllamaModelUrlField(), settings.getOllamaModelUrl()); - isModified |= isFieldModified(llmSettingsComponent.getLmStudioModelUrlField(), settings.getLmstudioModelUrl()); - isModified |= isFieldModified(llmSettingsComponent.getGpt4AllModelUrlField(), settings.getGpt4allModelUrl()); - isModified |= isFieldModified(llmSettingsComponent.getJanModelUrlField(), settings.getJanModelUrl()); - isModified |= isFieldModified(llmSettingsComponent.getExoModelUrlField(), settings.getExoModelUrl()); - isModified |= isFieldModified(llmSettingsComponent.getCustomOpenAIUrlField(), settings.getCustomOpenAIUrl()); - - isModified |= !settings.getShowAzureOpenAIFields().equals(llmSettingsComponent.getEnableAzureOpenAICheckBox().isSelected()); - isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIEndpointField(), settings.getAzureOpenAIEndpoint()); - isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIDeploymentField(), settings.getAzureOpenAIDeployment()); - isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIKeyField(), settings.getAzureOpenAIKey()); - - isModified |= settings.isOllamaEnabled() != llmSettingsComponent.getOllamaEnabledCheckBox().isSelected(); - isModified |= settings.isLmStudioEnabled() != llmSettingsComponent.getLmStudioEnabledCheckBox().isSelected(); - isModified |= settings.isGpt4AllEnabled() != llmSettingsComponent.getGpt4AllEnabledCheckBox().isSelected(); - isModified |= settings.isJanEnabled() != llmSettingsComponent.getJanEnabledCheckBox().isSelected(); - isModified |= settings.isExoEnabled() != llmSettingsComponent.getExoEnabledCheckBox().isSelected(); - isModified |= settings.isLlamaCPPEnabled() != llmSettingsComponent.getLlamaCPPEnabledCheckBox().isSelected(); - isModified |= settings.isJlamaEnabled() != llmSettingsComponent.getJlamaEnabledCheckBox().isSelected(); - isModified |= settings.isCustomOpenAIEnabled() != llmSettingsComponent.getCustomOpenAIEnabledCheckBox().isSelected(); - - isModified |= settings.isOpenAIEnabled() != llmSettingsComponent.getOpenAIEnabledCheckBox().isSelected(); - isModified |= settings.isMistralEnabled() != llmSettingsComponent.getMistralEnabledCheckBox().isSelected(); - isModified |= settings.isAnthropicEnabled() != llmSettingsComponent.getAnthropicEnabledCheckBox().isSelected(); - isModified |= settings.isGroqEnabled() != llmSettingsComponent.getGroqEnabledCheckBox().isSelected(); - isModified |= settings.isDeepInfraEnabled() != llmSettingsComponent.getDeepInfraEnabledCheckBox().isSelected(); - isModified |= settings.isGoogleEnabled() != llmSettingsComponent.getGeminiEnabledCheckBox().isSelected(); - isModified |= settings.isDeepSeekEnabled() != llmSettingsComponent.getDeepSeekEnabledCheckBox().isSelected(); - isModified |= settings.isOpenRouterEnabled() != llmSettingsComponent.getOpenRouterEnabledCheckBox().isSelected(); - isModified |= settings.getShowAzureOpenAIFields() != llmSettingsComponent.getEnableAzureOpenAICheckBox().isSelected(); + isModified |= !stateService.getStreamMode().equals(llmSettingsComponent.getStreamModeCheckBox().isSelected()); + + isModified |= isFieldModified(llmSettingsComponent.getOpenAIKeyField(), stateService.getOpenAIKey()); + isModified |= isFieldModified(llmSettingsComponent.getMistralApiKeyField(), stateService.getMistralKey()); + isModified |= isFieldModified(llmSettingsComponent.getAnthropicApiKeyField(), stateService.getAnthropicKey()); + isModified |= isFieldModified(llmSettingsComponent.getGroqApiKeyField(), stateService.getGroqKey()); + isModified |= isFieldModified(llmSettingsComponent.getDeepInfraApiKeyField(), stateService.getDeepInfraKey()); + isModified |= isFieldModified(llmSettingsComponent.getGeminiApiKeyField(), stateService.getGeminiKey()); + isModified |= isFieldModified(llmSettingsComponent.getDeepSeekApiKeyField(), stateService.getDeepSeekKey()); + isModified |= isFieldModified(llmSettingsComponent.getLlamaCPPModelUrlField(), stateService.getLlamaCPPUrl()); + isModified |= isFieldModified(llmSettingsComponent.getJlamaModelUrlField(), stateService.getJlamaUrl()); + isModified |= isFieldModified(llmSettingsComponent.getOpenRouterApiKeyField(), stateService.getOpenRouterKey()); + + isModified |= isFieldModified(llmSettingsComponent.getOllamaModelUrlField(), stateService.getOllamaModelUrl()); + isModified |= isFieldModified(llmSettingsComponent.getLmStudioModelUrlField(), stateService.getLmstudioModelUrl()); + isModified |= isFieldModified(llmSettingsComponent.getGpt4AllModelUrlField(), stateService.getGpt4allModelUrl()); + isModified |= isFieldModified(llmSettingsComponent.getJanModelUrlField(), stateService.getJanModelUrl()); + isModified |= isFieldModified(llmSettingsComponent.getExoModelUrlField(), stateService.getExoModelUrl()); + isModified |= isFieldModified(llmSettingsComponent.getCustomOpenAIUrlField(), stateService.getCustomOpenAIUrl()); + + isModified |= !stateService.getShowAzureOpenAIFields().equals(llmSettingsComponent.getEnableAzureOpenAICheckBox().isSelected()); + isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIEndpointField(), stateService.getAzureOpenAIEndpoint()); + isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIDeploymentField(), stateService.getAzureOpenAIDeployment()); + isModified |= isFieldModified(llmSettingsComponent.getAzureOpenAIKeyField(), stateService.getAzureOpenAIKey()); + + isModified |= stateService.isOllamaEnabled() != llmSettingsComponent.getOllamaEnabledCheckBox().isSelected(); + isModified |= stateService.isLmStudioEnabled() != llmSettingsComponent.getLmStudioEnabledCheckBox().isSelected(); + isModified |= stateService.isGpt4AllEnabled() != llmSettingsComponent.getGpt4AllEnabledCheckBox().isSelected(); + isModified |= stateService.isJanEnabled() != llmSettingsComponent.getJanEnabledCheckBox().isSelected(); + isModified |= stateService.isExoEnabled() != llmSettingsComponent.getExoEnabledCheckBox().isSelected(); + isModified |= stateService.isLlamaCPPEnabled() != llmSettingsComponent.getLlamaCPPEnabledCheckBox().isSelected(); + isModified |= stateService.isJlamaEnabled() != llmSettingsComponent.getJlamaEnabledCheckBox().isSelected(); + isModified |= stateService.isCustomOpenAIEnabled() != llmSettingsComponent.getCustomOpenAIEnabledCheckBox().isSelected(); + + isModified |= stateService.isOpenAIEnabled() != llmSettingsComponent.getOpenAIEnabledCheckBox().isSelected(); + isModified |= stateService.isMistralEnabled() != llmSettingsComponent.getMistralEnabledCheckBox().isSelected(); + isModified |= stateService.isAnthropicEnabled() != llmSettingsComponent.getAnthropicEnabledCheckBox().isSelected(); + isModified |= stateService.isGroqEnabled() != llmSettingsComponent.getGroqEnabledCheckBox().isSelected(); + isModified |= stateService.isDeepInfraEnabled() != llmSettingsComponent.getDeepInfraEnabledCheckBox().isSelected(); + isModified |= stateService.isGoogleEnabled() != llmSettingsComponent.getGeminiEnabledCheckBox().isSelected(); + isModified |= stateService.isDeepSeekEnabled() != llmSettingsComponent.getDeepSeekEnabledCheckBox().isSelected(); + isModified |= stateService.isOpenRouterEnabled() != llmSettingsComponent.getOpenRouterEnabledCheckBox().isSelected(); + isModified |= stateService.getShowAzureOpenAIFields() != llmSettingsComponent.getEnableAzureOpenAICheckBox().isSelected(); return isModified; } diff --git a/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersComponent.java b/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersComponent.java index 99b182a7..9a76253c 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersComponent.java +++ b/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersComponent.java @@ -7,6 +7,7 @@ import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -15,12 +16,18 @@ @Getter public class WebSearchProvidersComponent extends AbstractSettingsComponent { + @Getter private final JCheckBox enableWebSearchCheckbox = - new JCheckBox("", stateService.getEnableWebSearch()); + new JCheckBox("", stateService.getIsWebSearchEnabled()); + + @Getter + private final JCheckBox tavilySearchEnabledCheckBox = new JCheckBox("", stateService.isTavilySearchEnabled()); private final JPasswordField tavilySearchApiKeyField = new JPasswordField(stateService.getTavilySearchKey()); + @Getter + private final JCheckBox googleSearchEnabledCheckBox = new JCheckBox("", stateService.isGoogleSearchEnabled()); private final JPasswordField googleSearchApiKeyField = new JPasswordField(stateService.getGoogleSearchKey()); @@ -31,7 +38,6 @@ public class WebSearchProvidersComponent extends AbstractSettingsComponent { new JBIntSpinner(new UINumericRange(stateService.getMaxSearchResults(), 1, 10)); public WebSearchProvidersComponent() { - validateSearchElements(); addListeners(); } @@ -52,8 +58,8 @@ public JPanel createPanel() { JBLabel infoLabel = new JBLabel(); infoLabel.setText( "" + - "Post your prompt on the web using eitherGoogle search or Tavily search." + - ""); + "Post your prompt on the web using either Google search or Tavily search." + + ""); infoLabel.setForeground(UIUtil.getContextHelpForeground()); infoLabel.setBorder(JBUI.Borders.emptyBottom(10)); @@ -62,10 +68,10 @@ public JPanel createPanel() { gbc.gridy++; addSettingRow(panel, gbc, "Enable feature", enableWebSearchCheckbox); - addSettingRow(panel, gbc, "Tavily Web Search API Key", + addProviderSettingRow(panel, gbc, "Tavily Web Search API Key", tavilySearchEnabledCheckBox, createTextWithPasswordButton(tavilySearchApiKeyField, "https://app.tavily.com/home")); - addSettingRow(panel, gbc, "Google Web Search API Key", + addProviderSettingRow(panel, gbc, "Google Web Search API Key", googleSearchEnabledCheckBox, createTextWithPasswordButton(googleSearchApiKeyField, "https://developers.google.com/custom-search/docs/paid_element#api_key")); addSettingRow(panel, gbc, "Google Custom Search Engine ID", @@ -78,11 +84,42 @@ public JPanel createPanel() { @Override public void addListeners() { - enableWebSearchCheckbox.addItemListener( - event -> stateService.setEnableWebSearch(event.getStateChange() == ItemEvent.SELECTED)); + enableWebSearchCheckbox.addItemListener(e -> { + stateService.setIsWebSearchEnabled(e.getStateChange() == ItemEvent.SELECTED); + // Disable both providers when the feature is disabled + if (!enableWebSearchCheckbox.isSelected()) { + tavilySearchEnabledCheckBox.setSelected(false); + googleSearchEnabledCheckBox.setSelected(false); + updateUrlFieldState(tavilySearchEnabledCheckBox, tavilySearchApiKeyField); + updateUrlFieldState(googleSearchEnabledCheckBox, googleSearchApiKeyField); + } + }); + + tavilySearchEnabledCheckBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + // Disable Google Search if Tavily is selected + googleSearchEnabledCheckBox.setSelected(false); + stateService.setGoogleSearchEnabled(false); + updateUrlFieldState(googleSearchEnabledCheckBox, googleSearchApiKeyField); + } + stateService.setTavilySearchEnabled(tavilySearchEnabledCheckBox.isSelected()); + updateUrlFieldState(tavilySearchEnabledCheckBox, tavilySearchApiKeyField); + }); + + googleSearchEnabledCheckBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + // Disable Tavily if Google Search is selected + tavilySearchEnabledCheckBox.setSelected(false); + stateService.setTavilySearchEnabled(false); + updateUrlFieldState(tavilySearchEnabledCheckBox, tavilySearchApiKeyField); + } + stateService.setGoogleSearchEnabled(googleSearchEnabledCheckBox.isSelected()); + updateUrlFieldState(googleSearchEnabledCheckBox, googleSearchApiKeyField); + }); } - private void validateSearchElements() { - // TODO We need to check if either Google search URL or Tavily search URL is set to enable the search feature + private void updateUrlFieldState(@NotNull JCheckBox checkbox, + @NotNull JComponent urlComponent) { + urlComponent.setEnabled(checkbox.isSelected()); } } diff --git a/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersConfigurable.java b/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersConfigurable.java index aa7be4dc..813ced6a 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersConfigurable.java +++ b/src/main/java/com/devoxx/genie/ui/settings/websearch/WebSearchProvidersConfigurable.java @@ -49,19 +49,24 @@ public boolean isModified() { boolean isModified = false; - isModified |= !stateService.getEnableWebSearch().equals(webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected()); + isModified |= !stateService.getIsWebSearchEnabled().equals(webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected()); + webSearchProvidersComponent.getEnableWebSearchCheckbox().addItemListener(event -> { String text = webSearchProvidersComponent.getEnableWebSearchCheckbox().getText(); - stateService.setEnableWebSearch(text.equals("true")); + stateService.setIsWebSearchEnabled(text.equalsIgnoreCase("true")); }); boolean oldValue = stateService.getGitDiffEnabled(); boolean newValue = webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected(); - isModified |= webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected() != stateService.getEnableWebSearch(); + isModified |= webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected() != stateService.getIsWebSearchEnabled(); + isModified |= stateService.isTavilySearchEnabled() != webSearchProvidersComponent.getTavilySearchEnabledCheckBox().isSelected(); isModified |= isFieldModified(webSearchProvidersComponent.getTavilySearchApiKeyField(), stateService.getTavilySearchKey()); + + isModified |= stateService.isGoogleSearchEnabled() != webSearchProvidersComponent.getGoogleSearchEnabledCheckBox().isSelected(); isModified |= isFieldModified(webSearchProvidersComponent.getGoogleSearchApiKeyField(), stateService.getGoogleSearchKey()); isModified |= isFieldModified(webSearchProvidersComponent.getGoogleCSIApiKeyField(), stateService.getGoogleCSIKey()); + isModified |= webSearchProvidersComponent.getMaxSearchResults().getNumber() != stateService.getMaxSearchResults(); if (oldValue != newValue) { @@ -80,8 +85,10 @@ public boolean isModified() { public void apply() { DevoxxGenieStateService settings = DevoxxGenieStateService.getInstance(); - settings.setEnableWebSearch(webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected()); + settings.setIsWebSearchEnabled(webSearchProvidersComponent.getEnableWebSearchCheckbox().isSelected()); + settings.setTavilySearchEnabled(webSearchProvidersComponent.getTavilySearchEnabledCheckBox().isSelected()); settings.setTavilySearchKey(new String(webSearchProvidersComponent.getTavilySearchApiKeyField().getPassword())); + settings.setGoogleSearchEnabled(webSearchProvidersComponent.getGoogleSearchEnabledCheckBox().isSelected()); settings.setGoogleSearchKey(new String(webSearchProvidersComponent.getGoogleSearchApiKeyField().getPassword())); settings.setGoogleCSIKey(new String(webSearchProvidersComponent.getGoogleCSIApiKeyField().getPassword())); settings.setMaxSearchResults(webSearchProvidersComponent.getMaxSearchResults().getNumber()); @@ -94,9 +101,14 @@ public void apply() { public void reset() { DevoxxGenieStateService settings = DevoxxGenieStateService.getInstance(); - webSearchProvidersComponent.getEnableWebSearchCheckbox().setSelected(settings.getEnableWebSearch()); + webSearchProvidersComponent.getEnableWebSearchCheckbox().setSelected(settings.getIsWebSearchEnabled()); + + webSearchProvidersComponent.getTavilySearchEnabledCheckBox().setSelected(settings.isTavilySearchEnabled()); webSearchProvidersComponent.getTavilySearchApiKeyField().setText(settings.getTavilySearchKey()); + + webSearchProvidersComponent.getGoogleSearchEnabledCheckBox().setSelected(settings.isGoogleSearchEnabled()); webSearchProvidersComponent.getGoogleSearchApiKeyField().setText(settings.getGoogleSearchKey()); + webSearchProvidersComponent.getGoogleCSIApiKeyField().setText(settings.getGoogleCSIKey()); webSearchProvidersComponent.getMaxSearchResults().setValue(settings.getMaxSearchResults()); } diff --git a/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java b/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java index 84d0a371..b312be4f 100644 --- a/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java +++ b/src/main/java/com/devoxx/genie/util/ChatMessageContextUtil.java @@ -48,7 +48,7 @@ private ChatMessageContextUtil() { .userPrompt(userPromptText) .userMessage(UserMessage.userMessage(userPromptText)) .languageModel(languageModel) - .webSearchRequested(actionCommand.equals(TAVILY_SEARCH_ACTION) || actionCommand.equals(GOOGLE_SEARCH_ACTION)) + .webSearchRequested(stateService.getIsWebSearchEnabled() && (stateService.isGoogleSearchEnabled() || stateService.isTavilySearchEnabled())) .totalFileCount(FileListManager.getInstance().size()) .executionTimeMs(0) .cost(0) @@ -63,7 +63,7 @@ private ChatMessageContextUtil() { context.setTimeout(stateService.getTimeout() == ZERO_SECONDS ? SIXTY_SECONDS : stateService.getTimeout()); - setWindowContext(context, userPromptText, editorFileButtonManager, projectContext, isProjectContextAdded, actionCommand); + setWindowContext(context, userPromptText, editorFileButtonManager, projectContext, isProjectContextAdded); return context; } @@ -76,22 +76,14 @@ private ChatMessageContextUtil() { * @param editorFileButtonManager the editor file button manager * @param projectContext the project context * @param isProjectContextAdded the is project context added - * @param actionCommand the action command for setting the context for web requests */ private static void setWindowContext(@NotNull ChatMessageContext chatMessageContext, String userPrompt, EditorFileButtonManager editorFileButtonManager, String projectContext, - boolean isProjectContextAdded, - String actionCommand) { - - if (chatMessageContext.isWebSearchRequested()) { - if (actionCommand.equals(GOOGLE_SEARCH_ACTION)) { - chatMessageContext.setContext(GOOGLE_SEARCH_ACTION); - } else if (actionCommand.equals(TAVILY_SEARCH_ACTION)) { - chatMessageContext.setContext(TAVILY_SEARCH_ACTION); - } - } else if (projectContext != null && isProjectContextAdded) { + boolean isProjectContextAdded) { + + if (projectContext != null && isProjectContextAdded) { chatMessageContext.setContext(projectContext); } else { Editor selectedTextEditor = editorFileButtonManager.getSelectedTextEditor(); @@ -109,6 +101,12 @@ private static void setWindowContext(@NotNull ChatMessageContext chatMessageCont } } + /** + * Add the user selected files to chat message context. + * @param chatMessageContext the chat message context + * @param userPrompt the user prompt + * @param files the add files + */ private static void addSelectedFiles(@NotNull ChatMessageContext chatMessageContext, String userPrompt, List files) { @@ -128,6 +126,11 @@ private static void addEditorInfoToMessageContext(Editor editor, chatMessageContext.setEditorInfo(editorInfo); } + /** + * Check if the language model is an OpenAI O1 model because that doesn't support system prompts. + * @param languageModel the language model + * @return true if the language model is an OpenAI O1 model + */ public static boolean isOpenAIo1Model(LanguageModel languageModel) { return languageModel != null && languageModel.getProvider() == ModelProvider.OpenAI && diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b8de583c..8b941cc3 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -39,6 +39,7 @@
  • Feat #379: Cache file icons to increase performance
  • Fix #382: Restore the correct switch buttons states for RAG, Search, GitDiff
  • +
  • Fix #384: Fix web search with enable/disable of Google or Tavily feature

v0.4.4

    diff --git a/src/test/java/com/devoxx/genie/service/PromptExecutionServiceIT.java b/src/test/java/com/devoxx/genie/service/PromptExecutionServiceIT.java index 8a2f477e..1fc0f7bf 100644 --- a/src/test/java/com/devoxx/genie/service/PromptExecutionServiceIT.java +++ b/src/test/java/com/devoxx/genie/service/PromptExecutionServiceIT.java @@ -141,7 +141,7 @@ private ChatLanguageModel createChatModel(LanguageModel languageModel) { .apiKey(dotenv.get("MISTRAL_API_KEY")) .modelName(languageModel.getModelName()) .build(); - case DeepInfra + case DeepInfra -> OpenAiChatModel.builder() .baseUrl("https://api.deepinfra.com/v1/openai") .apiKey(dotenv.get("DEEPINFRA_API_KEY")) .modelName(languageModel.getModelName())