mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-16 19:44:36 +00:00
feat: improve tool window's textbox (#621)
* feat: initial smart user input panel implementation * refactor: clean up
This commit is contained in:
parent
5baab54697
commit
1fc47fa889
15 changed files with 965 additions and 462 deletions
|
|
@ -1,7 +1,14 @@
|
|||
package ee.carlrobert.codegpt.settings.service;
|
||||
|
||||
import static ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel.GPT_4_O;
|
||||
import static ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel.GPT_4_VISION_PREVIEW;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public enum ServiceType {
|
||||
|
|
@ -56,4 +63,26 @@ public enum ServiceType {
|
|||
}
|
||||
return serviceType;
|
||||
}
|
||||
|
||||
public boolean isImageActionSupported() {
|
||||
return switch (this) {
|
||||
case ANTHROPIC:
|
||||
case OLLAMA:
|
||||
yield true;
|
||||
case CODEGPT:
|
||||
var codegptModel = ApplicationManager.getApplication()
|
||||
.getService(CodeGPTServiceSettings.class)
|
||||
.getState()
|
||||
.getChatCompletionSettings()
|
||||
.getModel();
|
||||
yield List.of("gpt-4o", "claude-3-opus").contains(codegptModel);
|
||||
case OPENAI:
|
||||
var openaiModel = ApplicationManager.getApplication().getService(OpenAISettings.class)
|
||||
.getState()
|
||||
.getModel();
|
||||
yield List.of(GPT_4_VISION_PREVIEW.getCode(), GPT_4_O.getCode()).contains(openaiModel);
|
||||
default:
|
||||
yield false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
|
||||
var messageBusConnection = project.getMessageBus().connect();
|
||||
messageBusConnection.subscribe(IncludeFilesInContextNotifier.FILES_INCLUDED_IN_CONTEXT_TOPIC,
|
||||
(IncludeFilesInContextNotifier) this::displaySelectedFilesNotification);
|
||||
(IncludeFilesInContextNotifier) this::updateSelectedFilesNotification);
|
||||
messageBusConnection.subscribe(AttachImageNotifier.IMAGE_ATTACHMENT_FILE_PATH_TOPIC,
|
||||
(AttachImageNotifier) filePath -> imageFileAttachmentNotification.show(
|
||||
Path.of(filePath).getFileName().toString(),
|
||||
|
|
@ -95,8 +95,9 @@ public class ChatToolWindowPanel extends SimpleToolWindowPanel {
|
|||
return tabbedPane;
|
||||
}
|
||||
|
||||
public void displaySelectedFilesNotification(List<ReferencedFile> referencedFiles) {
|
||||
public void updateSelectedFilesNotification(List<ReferencedFile> referencedFiles) {
|
||||
if (referencedFiles.isEmpty()) {
|
||||
selectedFilesNotification.hideNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import static ee.carlrobert.codegpt.ui.UIUtil.createScrollPaneWithSmartScroller;
|
|||
import static java.lang.String.format;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.JBUI.Borders;
|
||||
import ee.carlrobert.codegpt.CodeGPTKeys;
|
||||
import ee.carlrobert.codegpt.EncodingManager;
|
||||
import ee.carlrobert.codegpt.ReferencedFile;
|
||||
|
|
@ -22,19 +20,16 @@ import ee.carlrobert.codegpt.completions.ConversationType;
|
|||
import ee.carlrobert.codegpt.conversations.Conversation;
|
||||
import ee.carlrobert.codegpt.conversations.ConversationService;
|
||||
import ee.carlrobert.codegpt.conversations.message.Message;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType;
|
||||
import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatToolWindowScrollablePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.UserMessagePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.ModelComboBoxAction;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensDetails;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.toolwindow.ui.ChatToolWindowLandingPanel;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.ui.textarea.UserInputPanel;
|
||||
import ee.carlrobert.codegpt.util.EditorUtil;
|
||||
import ee.carlrobert.codegpt.util.file.FileUtil;
|
||||
import java.awt.BorderLayout;
|
||||
|
|
@ -44,7 +39,6 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
|
@ -59,11 +53,13 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
private final Project project;
|
||||
private final JPanel rootPanel;
|
||||
private final Conversation conversation;
|
||||
private final UserPromptTextArea userPromptTextArea;
|
||||
private final UserInputPanel textArea;
|
||||
private final ConversationService conversationService;
|
||||
private final TotalTokensPanel totalTokensPanel;
|
||||
private final ChatToolWindowScrollablePanel toolWindowScrollablePanel;
|
||||
|
||||
private @Nullable CompletionRequestHandler requestHandler;
|
||||
|
||||
public ChatToolWindowTabPanel(@NotNull Project project, @NotNull Conversation conversation) {
|
||||
this.project = project;
|
||||
this.conversation = conversation;
|
||||
|
|
@ -74,10 +70,9 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
conversation,
|
||||
EditorUtil.getSelectedEditorSelectedText(project),
|
||||
this);
|
||||
userPromptTextArea = new UserPromptTextArea(this::handleSubmit, totalTokensPanel);
|
||||
textArea = new UserInputPanel(project, this::handleSubmit, this::handleCancel);
|
||||
textArea.requestFocus();
|
||||
rootPanel = createRootPanel();
|
||||
userPromptTextArea.requestFocusInWindow();
|
||||
userPromptTextArea.requestFocus();
|
||||
|
||||
if (conversation.getMessages().isEmpty()) {
|
||||
displayLandingView();
|
||||
|
|
@ -103,7 +98,7 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
}
|
||||
|
||||
public void requestFocusForTextArea() {
|
||||
userPromptTextArea.focus();
|
||||
textArea.requestFocus();
|
||||
}
|
||||
|
||||
public void displayLandingView() {
|
||||
|
|
@ -233,24 +228,23 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
return;
|
||||
}
|
||||
|
||||
var requestHandler = new CompletionRequestHandler(
|
||||
requestHandler = new CompletionRequestHandler(
|
||||
new ToolWindowCompletionResponseEventListener(
|
||||
conversationService,
|
||||
responsePanel,
|
||||
totalTokensPanel,
|
||||
userPromptTextArea) {
|
||||
textArea) {
|
||||
@Override
|
||||
public void handleTokensExceededPolicyAccepted() {
|
||||
call(callParameters, responsePanel);
|
||||
}
|
||||
});
|
||||
userPromptTextArea.setRequestHandler(requestHandler);
|
||||
userPromptTextArea.setSubmitEnabled(false);
|
||||
textArea.setSubmitEnabled(false);
|
||||
|
||||
requestHandler.call(callParameters);
|
||||
}
|
||||
|
||||
private void handleSubmit(String text) {
|
||||
private Unit handleSubmit(String text) {
|
||||
var message = new Message(text);
|
||||
var editor = EditorUtil.getSelectedEditor(project);
|
||||
if (editor != null) {
|
||||
|
|
@ -264,37 +258,27 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
}
|
||||
message.setUserMessage(text);
|
||||
sendMessage(message, ConversationType.DEFAULT);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
|
||||
private JPanel createUserPromptPanel(ServiceType selectedService) {
|
||||
private Unit handleCancel() {
|
||||
if (requestHandler != null) {
|
||||
requestHandler.cancel();
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
|
||||
private JPanel createUserPromptPanel() {
|
||||
var panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(JBUI.Borders.compound(
|
||||
JBUI.Borders.customLine(JBColor.border(), 1, 0, 0, 0),
|
||||
JBUI.Borders.empty(8)));
|
||||
var contentManager = project.getService(ChatToolWindowContentManager.class);
|
||||
panel.add(JBUI.Panels.simplePanel(createUserPromptTextAreaHeader(
|
||||
project,
|
||||
selectedService,
|
||||
(provider) -> {
|
||||
ConversationService.getInstance().startConversation();
|
||||
contentManager.createNewTabPanel();
|
||||
})), BorderLayout.NORTH);
|
||||
panel.add(JBUI.Panels.simplePanel(userPromptTextArea), BorderLayout.CENTER);
|
||||
panel.add(JBUI.Panels.simplePanel(totalTokensPanel)
|
||||
.withBorder(JBUI.Borders.emptyBottom(8)), BorderLayout.NORTH);
|
||||
panel.add(JBUI.Panels.simplePanel(textArea), BorderLayout.CENTER);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel createUserPromptTextAreaHeader(
|
||||
Project project,
|
||||
ServiceType selectedService,
|
||||
Consumer<ServiceType> onModelChange) {
|
||||
return JBUI.Panels.simplePanel()
|
||||
.withBorder(Borders.emptyBottom(8))
|
||||
.andTransparent()
|
||||
.addToLeft(totalTokensPanel)
|
||||
.addToRight(new ModelComboBoxAction(project, onModelChange, selectedService)
|
||||
.createCustomComponent(ActionPlaces.UNKNOWN));
|
||||
}
|
||||
|
||||
private JComponent getLandingView() {
|
||||
return new ChatToolWindowLandingPanel((action, locationOnScreen) -> {
|
||||
var editor = EditorUtil.getSelectedEditor(project);
|
||||
|
|
@ -354,8 +338,7 @@ public class ChatToolWindowTabPanel implements Disposable {
|
|||
gbc.weighty = 0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridy = 1;
|
||||
rootPanel.add(
|
||||
createUserPromptPanel(GeneralSettings.getSelectedService()), gbc);
|
||||
rootPanel.add(createUserPromptPanel(), gbc);
|
||||
return rootPanel;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import ee.carlrobert.codegpt.telemetry.TelemetryAction;
|
|||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ChatMessageResponseBody;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.TotalTokensPanel;
|
||||
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextArea;
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil;
|
||||
import ee.carlrobert.codegpt.ui.textarea.UserInputPanel;
|
||||
import ee.carlrobert.llm.client.openai.completion.ErrorDetails;
|
||||
import ee.carlrobert.llm.client.you.completion.YouSerpResult;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -37,7 +37,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
private final ResponsePanel responsePanel;
|
||||
private final ChatMessageResponseBody responseContainer;
|
||||
private final TotalTokensPanel totalTokensPanel;
|
||||
private final UserPromptTextArea userPromptTextArea;
|
||||
private final UserInputPanel textArea;
|
||||
|
||||
private volatile boolean completed;
|
||||
|
||||
|
|
@ -45,13 +45,13 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
ConversationService conversationService,
|
||||
ResponsePanel responsePanel,
|
||||
TotalTokensPanel totalTokensPanel,
|
||||
UserPromptTextArea userPromptTextArea) {
|
||||
UserInputPanel textArea) {
|
||||
this.encodingManager = EncodingManager.getInstance();
|
||||
this.conversationService = conversationService;
|
||||
this.responsePanel = responsePanel;
|
||||
this.responseContainer = (ChatMessageResponseBody) responsePanel.getContent();
|
||||
this.totalTokensPanel = totalTokensPanel;
|
||||
this.userPromptTextArea = userPromptTextArea;
|
||||
this.textArea = textArea;
|
||||
}
|
||||
|
||||
public abstract void handleTokensExceededPolicyAccepted();
|
||||
|
|
@ -127,7 +127,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
if (containsResults) {
|
||||
responseContainer.displaySerpResults(serpResults);
|
||||
}
|
||||
totalTokensPanel.updateUserPromptTokens(userPromptTextArea.getText());
|
||||
totalTokensPanel.updateUserPromptTokens(textArea.getText());
|
||||
totalTokensPanel.updateConversationTokens(callParameters.getConversation());
|
||||
} finally {
|
||||
stopStreaming(responseContainer);
|
||||
|
|
@ -142,7 +142,7 @@ abstract class ToolWindowCompletionResponseEventListener implements
|
|||
|
||||
private void stopStreaming(ChatMessageResponseBody responseContainer) {
|
||||
completed = true;
|
||||
userPromptTextArea.setSubmitEnabled(true);
|
||||
textArea.setSubmitEnabled(true);
|
||||
responseContainer.hideCaret();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class SelectedFilesAccordion extends JPanel {
|
|||
private JPanel createContentPanel(Project project, List<String> referencedFilePaths) {
|
||||
var panel = new JPanel();
|
||||
panel.setOpaque(false);
|
||||
panel.setVisible(false);
|
||||
panel.setVisible(true);
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||
panel.setBorder(JBUI.Borders.empty(4, 0));
|
||||
referencedFilePaths.stream()
|
||||
|
|
|
|||
|
|
@ -1,231 +0,0 @@
|
|||
package ee.carlrobert.codegpt.toolwindow.chat.ui.textarea;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.ANTHROPIC;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.CODEGPT;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OLLAMA;
|
||||
import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI;
|
||||
import static ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel.GPT_4_O;
|
||||
import static ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel.GPT_4_VISION_PREVIEW;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBTextArea;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.Icons;
|
||||
import ee.carlrobert.codegpt.actions.AttachImageAction;
|
||||
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.codegpt.CodeGPTServiceSettings;
|
||||
import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
|
||||
import ee.carlrobert.codegpt.ui.IconActionButton;
|
||||
import ee.carlrobert.codegpt.ui.UIUtil;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class UserPromptTextArea extends JPanel {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(UserPromptTextArea.class);
|
||||
|
||||
private static final JBColor BACKGROUND_COLOR = JBColor.namedColor(
|
||||
"Editor.SearchField.background", com.intellij.util.ui.UIUtil.getTextFieldBackground());
|
||||
|
||||
private final AtomicReference<CompletionRequestHandler> requestHandlerRef =
|
||||
new AtomicReference<>();
|
||||
private final JBTextArea textArea;
|
||||
private final int textAreaRadius = 16;
|
||||
private final Consumer<String> onSubmit;
|
||||
private IconActionButton stopButton;
|
||||
private boolean submitEnabled = true;
|
||||
|
||||
public UserPromptTextArea(Consumer<String> onSubmit, TotalTokensPanel totalTokensPanel) {
|
||||
super(new BorderLayout());
|
||||
this.onSubmit = onSubmit;
|
||||
|
||||
textArea = new JBTextArea();
|
||||
textArea.getDocument().addDocumentListener(getDocumentAdapter(totalTokensPanel));
|
||||
textArea.setOpaque(false);
|
||||
textArea.setBackground(BACKGROUND_COLOR);
|
||||
textArea.setLineWrap(true);
|
||||
textArea.setWrapStyleWord(true);
|
||||
textArea.getEmptyText().setText(CodeGPTBundle.get("toolwindow.chat.textArea.emptyText"));
|
||||
textArea.setBorder(JBUI.Borders.empty(8, 4));
|
||||
UIUtil.addShiftEnterInputMap(textArea, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
handleSubmit();
|
||||
} finally {
|
||||
totalTokensPanel.updateUserPromptTokens("");
|
||||
}
|
||||
}
|
||||
});
|
||||
textArea.addFocusListener(new FocusListener() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
UserPromptTextArea.super.paintBorder(UserPromptTextArea.super.getGraphics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
UserPromptTextArea.super.paintBorder(UserPromptTextArea.super.getGraphics());
|
||||
}
|
||||
});
|
||||
updateFont();
|
||||
init();
|
||||
}
|
||||
|
||||
private DocumentAdapter getDocumentAdapter(TotalTokensPanel totalTokensPanel) {
|
||||
return new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(@NotNull DocumentEvent event) {
|
||||
if (submitEnabled) {
|
||||
try {
|
||||
var document = event.getDocument();
|
||||
var text = document.getText(
|
||||
document.getStartPosition().getOffset(),
|
||||
document.getEndPosition().getOffset() - 1);
|
||||
totalTokensPanel.updateUserPromptTokens(text);
|
||||
} catch (BadLocationException ex) {
|
||||
LOG.error("Something went wrong while processing user input tokens", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return textArea.getText().trim();
|
||||
}
|
||||
|
||||
public void focus() {
|
||||
textArea.requestFocus();
|
||||
textArea.requestFocusInWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setColor(getBackground());
|
||||
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, textAreaRadius, textAreaRadius);
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBorder(Graphics g) {
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setColor(JBUI.CurrentTheme.ActionButton.focusedBorder());
|
||||
if (textArea.isFocusOwner()) {
|
||||
g2.setStroke(new BasicStroke(1.5F));
|
||||
}
|
||||
g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, textAreaRadius, textAreaRadius);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Insets getInsets() {
|
||||
return JBUI.insets(6, 12, 6, 6);
|
||||
}
|
||||
|
||||
public void setSubmitEnabled(boolean submitEnabled) {
|
||||
this.submitEnabled = submitEnabled;
|
||||
stopButton.setEnabled(!submitEnabled);
|
||||
}
|
||||
|
||||
public void setRequestHandler(@NotNull CompletionRequestHandler handler) {
|
||||
requestHandlerRef.set(handler);
|
||||
}
|
||||
|
||||
private void handleSubmit() {
|
||||
if (submitEnabled && !textArea.getText().isEmpty()) {
|
||||
// Replacing each newline with two newlines to ensure proper Markdown formatting
|
||||
var text = textArea.getText().replace("\n", "\n\n");
|
||||
onSubmit.accept(text.trim());
|
||||
textArea.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOpaque(false);
|
||||
add(textArea, BorderLayout.CENTER);
|
||||
|
||||
stopButton = new IconActionButton(
|
||||
new AnAction("Stop", "Stop current inference", AllIcons.Actions.Suspend) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
var handler = requestHandlerRef.get();
|
||||
if (handler != null) {
|
||||
handler.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
stopButton.setEnabled(false);
|
||||
|
||||
var flowLayout = new FlowLayout(FlowLayout.RIGHT);
|
||||
flowLayout.setHgap(8);
|
||||
JPanel iconsPanel = new JPanel(flowLayout);
|
||||
iconsPanel.add(new IconActionButton(
|
||||
new AnAction("Send Message", "Send message", Icons.Send) {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
handleSubmit();
|
||||
}
|
||||
}));
|
||||
if (isImageActionSupported()) {
|
||||
iconsPanel.add(new IconActionButton(new AttachImageAction()));
|
||||
}
|
||||
iconsPanel.add(stopButton);
|
||||
add(iconsPanel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
private boolean isImageActionSupported() {
|
||||
var selectedService = GeneralSettings.getSelectedService();
|
||||
if (selectedService == ANTHROPIC || selectedService == OLLAMA) {
|
||||
return true;
|
||||
}
|
||||
if (selectedService == CODEGPT) {
|
||||
var model = ApplicationManager.getApplication().getService(CodeGPTServiceSettings.class)
|
||||
.getState()
|
||||
.getChatCompletionSettings()
|
||||
.getModel();
|
||||
return List.of("gpt-4o", "claude-3-opus").contains(model);
|
||||
}
|
||||
|
||||
var model = OpenAISettings.getCurrentState().getModel();
|
||||
return selectedService == OPENAI && (
|
||||
GPT_4_VISION_PREVIEW.getCode().equals(model) || GPT_4_O.getCode().equals(model));
|
||||
}
|
||||
|
||||
private void updateFont() {
|
||||
if (Registry.is("ide.find.use.editor.font", false)) {
|
||||
textArea.setFont(EditorUtil.getEditorFont());
|
||||
} else {
|
||||
textArea.setFont(UIManager.getFont("TextField.font"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue