mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-19 16:28:46 +00:00
Improve multiple concurrent conversations (#54)
This commit is contained in:
parent
3e00703412
commit
b9abdbf0b0
17 changed files with 398 additions and 336 deletions
|
|
@ -4,7 +4,7 @@ import com.intellij.openapi.project.Project;
|
|||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import ee.carlrobert.codegpt.account.AccountDetailsState;
|
||||
import ee.carlrobert.codegpt.action.ActionsUtil;
|
||||
import ee.carlrobert.codegpt.client.ClientFactory;
|
||||
import ee.carlrobert.codegpt.client.ClientProvider;
|
||||
import ee.carlrobert.codegpt.settings.configuration.ConfigurationState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ public class PluginStartupActivity implements StartupActivity {
|
|||
ActionsUtil.refreshActions(ConfigurationState.getInstance().tableData);
|
||||
var accountDetails = AccountDetailsState.getInstance();
|
||||
if ("User".equals(accountDetails.accountName) || accountDetails.accountName == null) {
|
||||
ClientFactory.getBillingClient()
|
||||
ClientProvider.getBillingClient()
|
||||
.getSubscriptionAsync(subscription ->
|
||||
accountDetails.accountName = subscription.getAccountName());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ package ee.carlrobert.codegpt.action;
|
|||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import ee.carlrobert.codegpt.toolwindow.ContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AskAction extends AnAction {
|
||||
|
|
@ -22,14 +23,14 @@ public class AskAction extends AnAction {
|
|||
public void actionPerformed(@NotNull AnActionEvent event) {
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
var contentManagerService = project.getService(ContentManagerService.class);
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
contentManagerService.displayChatTab(project);
|
||||
contentManagerService.tryFindChatTabbedPane(project)
|
||||
.ifPresent(tabbedPane -> {
|
||||
var panel = new ChatToolWindowPanel(project);
|
||||
ConversationsState.getInstance().setCurrentConversation(null);
|
||||
var panel = new ChatToolWindowTabPanel(project);
|
||||
panel.displayLandingView();
|
||||
tabbedPane.addTab("Chat " + (tabbedPane.getTabCount() + 1), panel);
|
||||
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
|
||||
tabbedPane.addNewTab(panel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
|||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NlsActions;
|
||||
import ee.carlrobert.codegpt.toolwindow.ContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import javax.swing.Icon;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
@ -46,14 +47,15 @@ public abstract class BaseAction extends AnAction {
|
|||
}
|
||||
|
||||
protected void sendMessage(@NotNull Project project, String prompt) {
|
||||
var contentManagerService = project.getService(ContentManagerService.class);
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
contentManagerService.displayChatTab(project);
|
||||
contentManagerService.tryFindChatTabbedPane(project)
|
||||
.ifPresent(tabbedPane -> {
|
||||
var panel = new ChatToolWindowPanel(project);
|
||||
var conversation = ConversationsState.getInstance().startConversation();
|
||||
var panel = new ChatToolWindowTabPanel(project);
|
||||
panel.setConversationId(conversation.getId());
|
||||
panel.displayUserMessage(prompt);
|
||||
tabbedPane.addTab("Chat " + (tabbedPane.getTabCount() + 1), panel);
|
||||
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
|
||||
tabbedPane.addNewTab(panel);
|
||||
panel.sendMessage(prompt, project);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Proxy;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ClientFactory {
|
||||
public class ClientProvider {
|
||||
|
||||
public static BillingClient getBillingClient() {
|
||||
return getClientBuilder().buildBillingClient();
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package ee.carlrobert.codegpt.client;
|
||||
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.openai.client.completion.chat.request.ChatCompletionMessage;
|
||||
import ee.carlrobert.openai.client.completion.chat.request.ChatCompletionRequest;
|
||||
import ee.carlrobert.openai.client.completion.text.TextCompletionModel;
|
||||
|
|
@ -9,30 +8,30 @@ import ee.carlrobert.openai.client.completion.text.request.TextCompletionRequest
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ClientRequestFactory {
|
||||
public class CompletionRequestProvider {
|
||||
|
||||
private final String prompt;
|
||||
private final Conversation conversation;
|
||||
|
||||
public ClientRequestFactory(String prompt, Conversation conversation) {
|
||||
public CompletionRequestProvider(String prompt, Conversation conversation) {
|
||||
this.prompt = prompt;
|
||||
this.conversation = conversation;
|
||||
}
|
||||
|
||||
public ChatCompletionRequest buildChatCompletionRequest(SettingsState settings) {
|
||||
return new ChatCompletionRequest.Builder(buildMessages(prompt, conversation))
|
||||
.setModel(settings.chatCompletionBaseModel)
|
||||
public ChatCompletionRequest buildChatCompletionRequest(String model) {
|
||||
return new ChatCompletionRequest.Builder(buildMessages())
|
||||
.setModel(model)
|
||||
.build();
|
||||
}
|
||||
|
||||
public TextCompletionRequest buildTextCompletionRequest(SettingsState settings) {
|
||||
return new TextCompletionRequest.Builder(buildPrompt(conversation, prompt))
|
||||
public TextCompletionRequest buildTextCompletionRequest(String model) {
|
||||
return new TextCompletionRequest.Builder(buildPrompt(model))
|
||||
.setStop(List.of(" Human:", " AI:"))
|
||||
.setModel(settings.textCompletionBaseModel)
|
||||
.setModel(model)
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<ChatCompletionMessage> buildMessages(String prompt, Conversation conversation) {
|
||||
private List<ChatCompletionMessage> buildMessages() {
|
||||
var messages = new ArrayList<ChatCompletionMessage>();
|
||||
messages.add(new ChatCompletionMessage(
|
||||
"system",
|
||||
|
|
@ -45,8 +44,8 @@ public class ClientRequestFactory {
|
|||
return messages;
|
||||
}
|
||||
|
||||
private StringBuilder getBasePrompt() {
|
||||
var isDavinciModel = TextCompletionModel.DAVINCI.getCode().equals(SettingsState.getInstance().textCompletionBaseModel);
|
||||
private StringBuilder getBasePrompt(String model) {
|
||||
var isDavinciModel = TextCompletionModel.DAVINCI.getCode().equals(model);
|
||||
if (isDavinciModel) {
|
||||
return new StringBuilder(
|
||||
"You are ChatGPT, a large language model trained by OpenAI.\n" +
|
||||
|
|
@ -56,8 +55,8 @@ public class ClientRequestFactory {
|
|||
"The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly.\n\n");
|
||||
}
|
||||
|
||||
private String buildPrompt(Conversation conversation, String prompt) {
|
||||
var basePrompt = getBasePrompt();
|
||||
private String buildPrompt(String model) {
|
||||
var basePrompt = getBasePrompt(model);
|
||||
conversation.getMessages().forEach(message ->
|
||||
basePrompt.append("Human: ")
|
||||
.append(message.getPrompt())
|
||||
|
|
@ -12,6 +12,7 @@ import ee.carlrobert.codegpt.settings.SettingsState;
|
|||
import ee.carlrobert.openai.client.ClientCode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
|
@ -163,4 +164,13 @@ public class ConversationsState implements PersistentStateComponent<Conversation
|
|||
public Conversation getOrStartNew() {
|
||||
return currentConversation == null ? startConversation() : currentConversation;
|
||||
}
|
||||
|
||||
public Optional<Conversation> getConversation(UUID conversationId) {
|
||||
return conversationsContainer.getConversationsMapping()
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.filter(it -> conversationId.equals(it.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,14 @@
|
|||
package ee.carlrobert.codegpt.toolwindow;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionToolbar;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.SimpleToolWindowPanel;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowFactory;
|
||||
import com.intellij.ui.content.ContentManagerEvent;
|
||||
import com.intellij.ui.content.ContentManagerListener;
|
||||
import ee.carlrobert.codegpt.account.AccountDetailsState;
|
||||
import ee.carlrobert.codegpt.client.ClientFactory;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatTabbedPane;
|
||||
import ee.carlrobert.codegpt.client.ClientProvider;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.CreateNewConversationAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.OpenInEditorAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.UsageToolbarLabelAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.conversations.ConversationsToolWindow;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -25,17 +16,10 @@ import org.jetbrains.annotations.NotNull;
|
|||
public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
|
||||
|
||||
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
|
||||
var chatToolWindow = new ChatToolWindowPanel(project);
|
||||
var conversationsToolWindow = new ConversationsToolWindow(project);
|
||||
var toolWindowPanel = new SimpleToolWindowPanel(true);
|
||||
var chatToolWindowPanel = new ChatToolWindowPanel(project, toolWindow);
|
||||
|
||||
var chatTabbedPane = new ChatTabbedPane();
|
||||
chatTabbedPane.addTab("Chat 1", chatToolWindow);
|
||||
|
||||
toolWindowPanel.setToolbar(createActionToolbar(project, chatTabbedPane, toolWindowPanel).getComponent());
|
||||
toolWindowPanel.setContent(chatTabbedPane);
|
||||
|
||||
addContent(toolWindow, toolWindowPanel, "Chat");
|
||||
addContent(toolWindow, chatToolWindowPanel, "Chat");
|
||||
addContent(toolWindow, conversationsToolWindow.getContent(), "Conversation History");
|
||||
toolWindow.addContentManagerListener(new ContentManagerListener() {
|
||||
public void selectionChanged(@NotNull ContentManagerEvent event) {
|
||||
|
|
@ -43,7 +27,7 @@ public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
|
|||
if ("Conversation History".equals(content.getTabName()) && content.isSelected()) {
|
||||
conversationsToolWindow.refresh();
|
||||
} else if ("Chat".equals(content.getTabName()) && content.isSelected()) {
|
||||
ClientFactory.getBillingClient()
|
||||
ClientProvider.getBillingClient()
|
||||
.getCreditUsageAsync(creditUsage -> {
|
||||
var accountDetails = AccountDetailsState.getInstance();
|
||||
accountDetails.totalAmountGranted = creditUsage.getTotalGranted();
|
||||
|
|
@ -52,16 +36,6 @@ public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
var contentManagerService = project.getService(ContentManagerService.class);
|
||||
if (contentManagerService.isChatTabSelected(toolWindow.getContentManager())) {
|
||||
var conversation = ConversationsState.getCurrentConversation();
|
||||
if (conversation == null) {
|
||||
chatToolWindow.displayLandingView();
|
||||
} else {
|
||||
chatToolWindow.displayConversation(conversation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addContent(ToolWindow toolWindow, JComponent panel, String displayName) {
|
||||
|
|
@ -69,22 +43,4 @@ public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
|
|||
var content = contentManager.getFactory().createContent(panel, displayName, false);
|
||||
contentManager.addContent(content);
|
||||
}
|
||||
|
||||
private ActionToolbar createActionToolbar(Project project, ChatTabbedPane tabbedPane, SimpleToolWindowPanel toolWindowPanel) {
|
||||
var actionGroup = new DefaultActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new CreateNewConversationAction(() -> {
|
||||
tabbedPane.addTab("Chat " + (tabbedPane.getTabCount() + 1), new ChatToolWindowPanel(project));
|
||||
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
|
||||
toolWindowPanel.repaint();
|
||||
toolWindowPanel.revalidate();
|
||||
}));
|
||||
actionGroup.add(new OpenInEditorAction());
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(new UsageToolbarLabelAction());
|
||||
|
||||
// TODO: Data usage not enabled in stream mode https://community.openai.com/t/usage-info-in-api-responses/18862/11
|
||||
// actionGroup.add(new TokenToolbarLabelAction());
|
||||
|
||||
return ActionManager.getInstance().createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
package ee.carlrobert.codegpt.toolwindow;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import ee.carlrobert.codegpt.client.ClientFactory;
|
||||
import ee.carlrobert.codegpt.client.ClientRequestFactory;
|
||||
import ee.carlrobert.codegpt.client.ClientProvider;
|
||||
import ee.carlrobert.codegpt.client.CompletionRequestProvider;
|
||||
import ee.carlrobert.codegpt.client.EventListener;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea;
|
||||
import java.util.List;
|
||||
import javax.swing.SwingWorker;
|
||||
|
|
@ -20,7 +20,7 @@ public class ToolWindowService {
|
|||
SyntaxTextArea textArea,
|
||||
Project project,
|
||||
boolean isRetry,
|
||||
ChatToolWindowPanel toolWindow,
|
||||
ChatToolWindowTabPanel toolWindow,
|
||||
Conversation conversation) {
|
||||
var conversationMessage = new Message(prompt);
|
||||
|
||||
|
|
@ -38,13 +38,13 @@ public class ToolWindowService {
|
|||
|
||||
EventSource call;
|
||||
var settings = SettingsState.getInstance();
|
||||
var requestFactory = new ClientRequestFactory(prompt, conversation);
|
||||
var requestProvider = new CompletionRequestProvider(prompt, conversation);
|
||||
if (settings.isChatCompletionOptionSelected) {
|
||||
call = ClientFactory.getChatCompletionClient().stream(
|
||||
requestFactory.buildChatCompletionRequest(settings), eventListener);
|
||||
call = ClientProvider.getChatCompletionClient().stream(
|
||||
requestProvider.buildChatCompletionRequest(settings.chatCompletionBaseModel), eventListener);
|
||||
} else {
|
||||
call = ClientFactory.getTextCompletionClient().stream(
|
||||
requestFactory.buildTextCompletionRequest(settings), eventListener);
|
||||
call = ClientProvider.getTextCompletionClient().stream(
|
||||
requestProvider.buildTextCompletionRequest(settings.textCompletionBaseModel), eventListener);
|
||||
}
|
||||
toolWindow.displayGenerateButton(call::cancel);
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
package ee.carlrobert.codegpt.toolwindow;
|
||||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.ui.content.Content;
|
||||
import com.intellij.ui.content.ContentManager;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatTabbedPane;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ContentManagerService {
|
||||
public class ChatContentManagerService {
|
||||
|
||||
public void displayChatTab(@NotNull Project project) {
|
||||
var toolWindow = requireNonNull(ToolWindowManager.getInstance(project).getToolWindow("CodeGPT"));
|
||||
var toolWindow = getToolWindow(project);
|
||||
toolWindow.show();
|
||||
var contentManager = toolWindow.getContentManager();
|
||||
tryFindChatTabContent(contentManager).ifPresentOrElse(
|
||||
|
|
@ -23,12 +23,6 @@ public class ContentManagerService {
|
|||
);
|
||||
}
|
||||
|
||||
public Optional<Content> tryFindChatTabContent(ContentManager contentManager) {
|
||||
return Arrays.stream(contentManager.getContents())
|
||||
.filter(content -> "Chat".equals(content.getTabName()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public boolean isChatTabSelected(ContentManager contentManager) {
|
||||
return tryFindChatTabContent(contentManager)
|
||||
.filter(contentManager::isSelected)
|
||||
|
|
@ -36,8 +30,7 @@ public class ContentManagerService {
|
|||
}
|
||||
|
||||
public Optional<ChatTabbedPane> tryFindChatTabbedPane(@NotNull Project project) {
|
||||
var toolWindow = requireNonNull(ToolWindowManager.getInstance(project).getToolWindow("CodeGPT"));
|
||||
var chatTabContent = tryFindChatTabContent(toolWindow.getContentManager());
|
||||
var chatTabContent = tryFindChatTabContent(getToolWindow(project).getContentManager());
|
||||
if (chatTabContent.isPresent()) {
|
||||
var tabbedPane = Arrays.stream(chatTabContent.get().getComponent().getComponents())
|
||||
.filter(component -> component instanceof ChatTabbedPane)
|
||||
|
|
@ -48,4 +41,23 @@ public class ContentManagerService {
|
|||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void resetTabbedPane(@NotNull Project project) {
|
||||
tryFindChatTabbedPane(project).ifPresent(tabbedPane -> {
|
||||
tabbedPane.removeAll();
|
||||
var tabPanel = new ChatToolWindowTabPanel(project);
|
||||
tabPanel.displayLandingView();
|
||||
tabbedPane.addNewTab(tabPanel);
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<Content> tryFindChatTabContent(ContentManager contentManager) {
|
||||
return Arrays.stream(contentManager.getContents())
|
||||
.filter(content -> "Chat".equals(content.getTabName()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private ToolWindow getToolWindow(@NotNull Project project) {
|
||||
return requireNonNull(ToolWindowManager.getInstance(project).getToolWindow("CodeGPT"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
@ -8,15 +10,19 @@ import java.util.UUID;
|
|||
|
||||
public class ChatTabbedPane extends JBTabbedPane {
|
||||
|
||||
private final Map<Integer, ChatToolWindowPanel> activeTabMapping = new HashMap<>();
|
||||
private final Map<Integer, ChatToolWindowTabPanel> activeTabMapping = new HashMap<>();
|
||||
|
||||
public ChatTabbedPane() {
|
||||
setTabComponentInsets(null);
|
||||
addChangeListener(e -> tryFindCurrentlyActiveConversation()
|
||||
.ifPresent(conversation -> ConversationsState.getInstance().setCurrentConversation(conversation)));
|
||||
}
|
||||
|
||||
public void addTab(String title, ChatToolWindowPanel toolWindowPanel) {
|
||||
super.addTab(title, toolWindowPanel.getContent());
|
||||
activeTabMapping.put(getTabCount() - 1, toolWindowPanel);
|
||||
public void addNewTab(ChatToolWindowTabPanel toolWindowPanel) {
|
||||
super.addTab("Chat " + (getTabCount() + 1), toolWindowPanel.getContent());
|
||||
var tabIndex = getTabCount() - 1;
|
||||
super.setSelectedIndex(tabIndex);
|
||||
activeTabMapping.put(tabIndex, toolWindowPanel);
|
||||
}
|
||||
|
||||
public Optional<Integer> tryFindActiveConversationIndex(UUID conversationId) {
|
||||
|
|
@ -25,4 +31,12 @@ public class ChatTabbedPane extends JBTabbedPane {
|
|||
.findFirst()
|
||||
.map(Map.Entry::getKey);
|
||||
}
|
||||
|
||||
public Optional<Conversation> tryFindCurrentlyActiveConversation() {
|
||||
var toolWindowPanel = activeTabMapping.get(getSelectedIndex());
|
||||
if (toolWindowPanel == null || toolWindowPanel.getConversationId() == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return ConversationsState.getInstance().getConversation(toolWindowPanel.getConversationId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,241 +1,65 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.createIconLabel;
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.createTextPane;
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.justifyLeft;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionToolbar;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import ee.carlrobert.codegpt.account.AccountDetailsState;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import com.intellij.openapi.ui.SimpleToolWindowPanel;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.SettingsConfigurable;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.ToolWindowService;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.GenerateButton;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.LandingView;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.ScrollPane;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.TextArea;
|
||||
import icons.Icons;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.CreateNewConversationAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.OpenInEditorAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.actions.UsageToolbarLabelAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChatToolWindowPanel {
|
||||
public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
||||
|
||||
private static final List<SyntaxTextArea> textAreas = new ArrayList<>();
|
||||
private final Project project;
|
||||
private JPanel chatGptToolWindowContent;
|
||||
private ScrollPane scrollPane;
|
||||
private ScrollablePanel scrollablePanel;
|
||||
private JTextArea textArea;
|
||||
private JScrollPane textAreaScrollPane;
|
||||
private GenerateButton generateButton;
|
||||
private boolean isLandingViewVisible;
|
||||
private UUID conversationId;
|
||||
|
||||
public ChatToolWindowPanel(@NotNull Project project) {
|
||||
this.project = project;
|
||||
public ChatToolWindowPanel(@NotNull Project project, @NotNull ToolWindow toolWindow) {
|
||||
super(true);
|
||||
initialize(project, toolWindow);
|
||||
}
|
||||
|
||||
public JPanel getContent() {
|
||||
return chatGptToolWindowContent;
|
||||
}
|
||||
private void initialize(Project project, ToolWindow toolWindow) {
|
||||
var tabPanel = new ChatToolWindowTabPanel(project);
|
||||
var tabbedPane = createTabbedPane(tabPanel);
|
||||
setToolbar(createActionToolbar(project, tabbedPane).getComponent());
|
||||
setContent(tabbedPane);
|
||||
|
||||
public void displayUserMessage(String userMessage) {
|
||||
addIconLabel(AllIcons.General.User, AccountDetailsState.getInstance().accountName);
|
||||
scrollablePanel.add(createTextPane(userMessage));
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
public void displayLandingView() {
|
||||
if (!isLandingViewVisible) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
clearWindow();
|
||||
isLandingViewVisible = true;
|
||||
|
||||
addSpacing(16);
|
||||
var landingView = new LandingView();
|
||||
scrollablePanel.add(landingView.createImageIconPanel());
|
||||
addSpacing(16);
|
||||
landingView.getQuestionPanels().forEach(panel -> {
|
||||
scrollablePanel.add(panel);
|
||||
addSpacing(16);
|
||||
});
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void displayConversation(Conversation conversation) {
|
||||
setConversationId(conversation.getId());
|
||||
clearWindow();
|
||||
conversation.getMessages().forEach(message -> {
|
||||
displayUserMessage(message.getPrompt());
|
||||
addIconLabel(Icons.DefaultImageIcon, "ChatGPT");
|
||||
var textArea = new SyntaxTextArea(true, false, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
textArea.setText(message.getResponse());
|
||||
textArea.displayCopyButton();
|
||||
scrollablePanel.add(textArea);
|
||||
textAreas.add(textArea);
|
||||
});
|
||||
scrollToBottom();
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
public void sendMessage(String prompt, Project project) {
|
||||
sendMessage(prompt, project, false);
|
||||
}
|
||||
|
||||
public void sendMessage(String prompt, Project project, boolean isRetry) {
|
||||
if (!isRetry) {
|
||||
addIconLabel(Icons.DefaultImageIcon, "ChatGPT");
|
||||
}
|
||||
|
||||
var settings = SettingsState.getInstance();
|
||||
if (settings.apiKey.isEmpty()) {
|
||||
notifyMissingCredential(project, "API key not provided.");
|
||||
} else {
|
||||
SyntaxTextArea textArea;
|
||||
if (isRetry) {
|
||||
textArea = textAreas.get(textAreas.size() - 1);
|
||||
textArea.clear();
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
if (contentManagerService.isChatTabSelected(toolWindow.getContentManager())) {
|
||||
var conversation = ConversationsState.getCurrentConversation();
|
||||
if (conversation == null) {
|
||||
tabPanel.displayLandingView();
|
||||
} else {
|
||||
textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
addTextArea(textArea);
|
||||
tabPanel.displayConversation(conversation);
|
||||
}
|
||||
|
||||
var conversation = ConversationsState.getInstance().getOrStartNew();
|
||||
setConversationId(conversation.getId());
|
||||
project.getService(ToolWindowService.class)
|
||||
.startRequest(prompt, textArea, project, isRetry, this, conversation);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearWindow() {
|
||||
isLandingViewVisible = false;
|
||||
generateButton.setVisible(false);
|
||||
textAreas.clear();
|
||||
scrollablePanel.removeAll();
|
||||
private ActionToolbar createActionToolbar(Project project, ChatTabbedPane tabbedPane) {
|
||||
var actionGroup = new DefaultActionGroup("TOOLBAR_ACTION_GROUP", false);
|
||||
actionGroup.add(new CreateNewConversationAction(() -> {
|
||||
var conversation = ConversationsState.getInstance().startConversation();
|
||||
var panel = new ChatToolWindowTabPanel(project);
|
||||
panel.setConversationId(conversation.getId());
|
||||
panel.displayLandingView();
|
||||
tabbedPane.addNewTab(panel);
|
||||
repaint();
|
||||
revalidate();
|
||||
}));
|
||||
actionGroup.add(new OpenInEditorAction());
|
||||
actionGroup.addSeparator();
|
||||
actionGroup.add(new UsageToolbarLabelAction());
|
||||
|
||||
// TODO: Data usage not enabled in stream mode https://community.openai.com/t/usage-info-in-api-responses/18862/11
|
||||
// actionGroup.add(new TokenToolbarLabelAction());
|
||||
|
||||
return ActionManager.getInstance().createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, false);
|
||||
}
|
||||
|
||||
public void addSpacing(int height) {
|
||||
scrollablePanel.add(Box.createVerticalStrut(height));
|
||||
}
|
||||
|
||||
public void addIconLabel(Icon icon, String text) {
|
||||
addSpacing(8);
|
||||
scrollablePanel.add(justifyLeft(createIconLabel(icon, text)));
|
||||
addSpacing(8);
|
||||
}
|
||||
|
||||
public void notifyMissingCredential(Project project, String text) {
|
||||
var label = new JLabel(format("<html>%s <font color='#589df6'><u>Open Settings</u></font> to set one.</html>", text));
|
||||
label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
label.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(project, SettingsConfigurable.class);
|
||||
}
|
||||
});
|
||||
scrollablePanel.add(justifyLeft(label));
|
||||
}
|
||||
|
||||
public void displayGenerateButton(Runnable onClick) {
|
||||
generateButton.setVisible(true);
|
||||
generateButton.setMode(GenerateButton.Mode.STOP, onClick);
|
||||
}
|
||||
|
||||
public void stopGenerating(String prompt, SyntaxTextArea textArea, Project project) {
|
||||
generateButton.setMode(GenerateButton.Mode.REFRESH, () -> {
|
||||
sendMessage(prompt, project, true);
|
||||
scrollToBottom();
|
||||
});
|
||||
textArea.displayCopyButton();
|
||||
textArea.getCaret().setVisible(false);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
public void scrollToBottom() {
|
||||
scrollPane.scrollToBottom();
|
||||
}
|
||||
|
||||
public void addTextArea(SyntaxTextArea textArea) {
|
||||
scrollablePanel.add(textArea);
|
||||
textAreas.add(textArea);
|
||||
}
|
||||
|
||||
public void changeStyle() {
|
||||
for (var textArea : textAreas) {
|
||||
textArea.changeStyleViaThemeXml();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSubmit() {
|
||||
var searchText = textArea.getText();
|
||||
if (isLandingViewVisible || ConversationsState.getCurrentConversation() == null) {
|
||||
clearWindow();
|
||||
}
|
||||
displayUserMessage(searchText);
|
||||
sendMessage(searchText, project);
|
||||
textArea.setText("");
|
||||
scrollToBottom();
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
textAreaScrollPane = new JBScrollPane() {
|
||||
public JScrollBar createVerticalScrollBar() {
|
||||
JScrollBar verticalScrollBar = new JScrollPane.ScrollBar(1);
|
||||
verticalScrollBar.setPreferredSize(new Dimension(0, 0));
|
||||
return verticalScrollBar;
|
||||
}
|
||||
};
|
||||
textAreaScrollPane.setBorder(null);
|
||||
textAreaScrollPane.setViewportBorder(null);
|
||||
textAreaScrollPane.setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createMatteBorder(1, 0, 0, 0, JBColor.border()),
|
||||
BorderFactory.createEmptyBorder(0, 5, 0, 10)));
|
||||
textArea = new TextArea(this::handleSubmit, textAreaScrollPane);
|
||||
textAreaScrollPane.setViewportView(textArea);
|
||||
|
||||
scrollablePanel = new ScrollablePanel();
|
||||
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
|
||||
scrollPane = new ScrollPane(scrollablePanel);
|
||||
|
||||
generateButton = new GenerateButton();
|
||||
}
|
||||
|
||||
public UUID getConversationId() {
|
||||
return conversationId;
|
||||
}
|
||||
|
||||
public void setConversationId(UUID conversationId) {
|
||||
this.conversationId = conversationId;
|
||||
private ChatTabbedPane createTabbedPane(ChatToolWindowTabPanel tabPanel) {
|
||||
var tabbedPane = new ChatTabbedPane();
|
||||
tabbedPane.addNewTab(tabPanel);
|
||||
return tabbedPane;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel">
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel">
|
||||
<grid id="27dc6" binding="chatGptToolWindowContent" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat;
|
||||
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.createIconLabel;
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.createTextPane;
|
||||
import static ee.carlrobert.codegpt.util.SwingUtils.justifyLeft;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import ee.carlrobert.codegpt.account.AccountDetailsState;
|
||||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.SettingsConfigurable;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.ToolWindowService;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.GenerateButton;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.LandingView;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.ScrollPane;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.SyntaxTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.components.TextArea;
|
||||
import icons.Icons;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChatToolWindowTabPanel {
|
||||
|
||||
private static final List<SyntaxTextArea> textAreas = new ArrayList<>();
|
||||
private final Project project;
|
||||
private JPanel chatGptToolWindowContent;
|
||||
private ScrollPane scrollPane;
|
||||
private ScrollablePanel scrollablePanel;
|
||||
private JTextArea textArea;
|
||||
private JScrollPane textAreaScrollPane;
|
||||
private GenerateButton generateButton;
|
||||
private boolean isLandingViewVisible;
|
||||
private UUID conversationId;
|
||||
|
||||
public ChatToolWindowTabPanel(@NotNull Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public JPanel getContent() {
|
||||
return chatGptToolWindowContent;
|
||||
}
|
||||
|
||||
public void displayUserMessage(String userMessage) {
|
||||
addIconLabel(AllIcons.General.User, AccountDetailsState.getInstance().accountName);
|
||||
scrollablePanel.add(createTextPane(userMessage));
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
public void displayLandingView() {
|
||||
if (!isLandingViewVisible) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
clearWindow();
|
||||
isLandingViewVisible = true;
|
||||
|
||||
addSpacing(16);
|
||||
var landingView = new LandingView();
|
||||
scrollablePanel.add(landingView.createImageIconPanel());
|
||||
addSpacing(16);
|
||||
landingView.getQuestionPanels().forEach(panel -> {
|
||||
scrollablePanel.add(panel);
|
||||
addSpacing(16);
|
||||
});
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void displayConversation(Conversation conversation) {
|
||||
setConversationId(conversation.getId());
|
||||
clearWindow();
|
||||
conversation.getMessages().forEach(message -> {
|
||||
displayUserMessage(message.getPrompt());
|
||||
addIconLabel(Icons.DefaultImageIcon, "ChatGPT");
|
||||
var textArea = new SyntaxTextArea(true, false, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
textArea.setText(message.getResponse());
|
||||
textArea.displayCopyButton();
|
||||
scrollablePanel.add(textArea);
|
||||
textAreas.add(textArea);
|
||||
});
|
||||
scrollToBottom();
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
public void sendMessage(String prompt, Project project) {
|
||||
sendMessage(prompt, project, false);
|
||||
}
|
||||
|
||||
public void sendMessage(String prompt, Project project, boolean isRetry) {
|
||||
if (!isRetry) {
|
||||
addIconLabel(Icons.DefaultImageIcon, "ChatGPT");
|
||||
}
|
||||
|
||||
var settings = SettingsState.getInstance();
|
||||
if (settings.apiKey.isEmpty()) {
|
||||
notifyMissingCredential(project, "API key not provided.");
|
||||
} else {
|
||||
SyntaxTextArea textArea;
|
||||
if (isRetry) {
|
||||
textArea = textAreas.get(textAreas.size() - 1);
|
||||
textArea.clear();
|
||||
} else {
|
||||
textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
addTextArea(textArea);
|
||||
}
|
||||
|
||||
var conversation = ConversationsState.getInstance().getOrStartNew();
|
||||
setConversationId(conversation.getId());
|
||||
project.getService(ToolWindowService.class)
|
||||
.startRequest(prompt, textArea, project, isRetry, this, conversation);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearWindow() {
|
||||
isLandingViewVisible = false;
|
||||
generateButton.setVisible(false);
|
||||
textAreas.clear();
|
||||
scrollablePanel.removeAll();
|
||||
}
|
||||
|
||||
public void addSpacing(int height) {
|
||||
scrollablePanel.add(Box.createVerticalStrut(height));
|
||||
}
|
||||
|
||||
public void addIconLabel(Icon icon, String text) {
|
||||
addSpacing(8);
|
||||
scrollablePanel.add(justifyLeft(createIconLabel(icon, text)));
|
||||
addSpacing(8);
|
||||
}
|
||||
|
||||
public void notifyMissingCredential(Project project, String text) {
|
||||
var label = new JLabel(format("<html>%s <font color='#589df6'><u>Open Settings</u></font> to set one.</html>", text));
|
||||
label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
label.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(project, SettingsConfigurable.class);
|
||||
}
|
||||
});
|
||||
scrollablePanel.add(justifyLeft(label));
|
||||
}
|
||||
|
||||
public void displayGenerateButton(Runnable onClick) {
|
||||
generateButton.setVisible(true);
|
||||
generateButton.setMode(GenerateButton.Mode.STOP, onClick);
|
||||
}
|
||||
|
||||
public void stopGenerating(String prompt, SyntaxTextArea textArea, Project project) {
|
||||
generateButton.setMode(GenerateButton.Mode.REFRESH, () -> {
|
||||
sendMessage(prompt, project, true);
|
||||
scrollToBottom();
|
||||
});
|
||||
textArea.displayCopyButton();
|
||||
textArea.getCaret().setVisible(false);
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
public void scrollToBottom() {
|
||||
scrollPane.scrollToBottom();
|
||||
}
|
||||
|
||||
public void addTextArea(SyntaxTextArea textArea) {
|
||||
scrollablePanel.add(textArea);
|
||||
textAreas.add(textArea);
|
||||
}
|
||||
|
||||
public void changeStyle() {
|
||||
for (var textArea : textAreas) {
|
||||
textArea.changeStyleViaThemeXml();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSubmit() {
|
||||
var searchText = textArea.getText();
|
||||
if (isLandingViewVisible || ConversationsState.getCurrentConversation() == null) {
|
||||
clearWindow();
|
||||
}
|
||||
displayUserMessage(searchText);
|
||||
sendMessage(searchText, project);
|
||||
textArea.setText("");
|
||||
scrollToBottom();
|
||||
scrollablePanel.revalidate();
|
||||
scrollablePanel.repaint();
|
||||
}
|
||||
|
||||
private void createUIComponents() {
|
||||
textAreaScrollPane = new JBScrollPane() {
|
||||
public JScrollBar createVerticalScrollBar() {
|
||||
JScrollBar verticalScrollBar = new JScrollPane.ScrollBar(1);
|
||||
verticalScrollBar.setPreferredSize(new Dimension(0, 0));
|
||||
return verticalScrollBar;
|
||||
}
|
||||
};
|
||||
textAreaScrollPane.setBorder(null);
|
||||
textAreaScrollPane.setViewportBorder(null);
|
||||
textAreaScrollPane.setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createMatteBorder(1, 0, 0, 0, JBColor.border()),
|
||||
BorderFactory.createEmptyBorder(0, 5, 0, 10)));
|
||||
textArea = new TextArea(this::handleSubmit, textAreaScrollPane);
|
||||
textAreaScrollPane.setViewportView(textArea);
|
||||
|
||||
scrollablePanel = new ScrollablePanel();
|
||||
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
|
||||
scrollPane = new ScrollPane(scrollablePanel);
|
||||
|
||||
generateButton = new GenerateButton();
|
||||
}
|
||||
|
||||
public UUID getConversationId() {
|
||||
return conversationId;
|
||||
}
|
||||
|
||||
public void setConversationId(UUID conversationId) {
|
||||
this.conversationId = conversationId;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package ee.carlrobert.codegpt.toolwindow.chat.actions;
|
|||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CreateNewConversationAction extends AnAction {
|
||||
|
|
@ -19,7 +18,6 @@ public class CreateNewConversationAction extends AnAction {
|
|||
public void actionPerformed(@NotNull AnActionEvent event) {
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
ConversationsState.getInstance().startConversation();
|
||||
onCreate.run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import com.intellij.util.ui.JBUI;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.settings.SettingsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.ContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatContentManagerService;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.conversations.actions.ClearAllConversationsAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.conversations.actions.DeleteConversationAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.conversations.actions.MoveDownAction;
|
||||
|
|
@ -77,16 +77,14 @@ public class ConversationsToolWindow {
|
|||
ConversationsState.getInstance().setCurrentConversation(conversation);
|
||||
changeSettings(conversation);
|
||||
|
||||
var contentManagerService = project.getService(ContentManagerService.class);
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
contentManagerService.displayChatTab(project);
|
||||
contentManagerService.tryFindChatTabbedPane(project)
|
||||
.ifPresent(tabbedPane -> tabbedPane.tryFindActiveConversationIndex(conversation.getId())
|
||||
.ifPresentOrElse(tabbedPane::setSelectedIndex, () -> {
|
||||
var panel = new ChatToolWindowPanel(project);
|
||||
var panel = new ChatToolWindowTabPanel(project);
|
||||
panel.displayConversation(conversation);
|
||||
|
||||
tabbedPane.addTab("Chat " + (tabbedPane.getTabCount() + 1), panel);
|
||||
tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
|
||||
tabbedPane.addNewTab(panel);
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.conversations.actions;
|
||||
|
||||
import static icons.Icons.DefaultImageIcon;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationsState;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ChatContentManagerService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import static icons.Icons.DefaultImageIcon;
|
||||
|
||||
public class ClearAllConversationsAction extends AnAction {
|
||||
|
||||
|
|
@ -22,6 +24,11 @@ public class ClearAllConversationsAction extends AnAction {
|
|||
int answer = Messages.showYesNoDialog("Are you sure you want to delete all conversations?", "Clear History", DefaultImageIcon);
|
||||
if (answer == Messages.YES) {
|
||||
ConversationsState.getInstance().clearAll();
|
||||
var project = event.getProject();
|
||||
if (project != null) {
|
||||
var contentManagerService = project.getService(ChatContentManagerService.class);
|
||||
contentManagerService.resetTabbedPane(project);
|
||||
}
|
||||
this.onRefresh.run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@
|
|||
<applicationService serviceImplementation="ee.carlrobert.codegpt.conversations.ConversationsState"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.account.AccountDetailsState"/>
|
||||
<projectService serviceImplementation="ee.carlrobert.codegpt.toolwindow.ToolWindowService"/>
|
||||
<projectService serviceImplementation="ee.carlrobert.codegpt.toolwindow.ContentManagerService"/>
|
||||
<projectService serviceImplementation="ee.carlrobert.codegpt.toolwindow.chat.ChatContentManagerService"/>
|
||||
<toolWindow id="CodeGPT" icon="Icons.ToolWindowIcon" anchor="right"
|
||||
factoryClass="ee.carlrobert.codegpt.toolwindow.ProjectToolWindowFactory"/>
|
||||
</extensions>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue