mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-06 16:22:19 +00:00
1.1.6 - Ability to execute custom prompts, add block caret when typing, other improvements
This commit is contained in:
parent
484511294d
commit
fa1e2a486b
14 changed files with 192 additions and 67 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package ee.carlrobert.chatgpt.client.chatgpt;
|
||||
|
||||
import com.fasterxml.jackson.core.JacksonException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import ee.carlrobert.chatgpt.client.Subscriber;
|
||||
import ee.carlrobert.chatgpt.client.chatgpt.response.ChatGPTResponse;
|
||||
|
|
@ -27,11 +29,11 @@ public class ChatGPTBodySubscriber extends Subscriber<ChatGPTResponse> {
|
|||
}
|
||||
|
||||
protected void onErrorOccurred() {
|
||||
responseConsumer.accept("Something went wrong. Please try again later.");
|
||||
responseConsumer.accept("\nSomething went wrong. Please try again later.");
|
||||
}
|
||||
|
||||
protected void send(String responsePayload, String token) {
|
||||
if (!responsePayload.isEmpty()) {
|
||||
if (!responsePayload.isEmpty() && isValidJson(responsePayload)) {
|
||||
try {
|
||||
var response = objectMapper.readValue(responsePayload, ChatGPTResponse.class);
|
||||
var author = response.getMessage().getAuthor();
|
||||
|
|
@ -47,11 +49,13 @@ public class ChatGPTBodySubscriber extends Subscriber<ChatGPTResponse> {
|
|||
throw new RuntimeException("Unable to deserialize the payload", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
var response = objectMapper.readValue(token, ChatGPTResponseDetail.class);
|
||||
this.responseConsumer.accept(response.getDetail());
|
||||
} catch (JsonProcessingException e) {
|
||||
tryProcessingErrorResponse(token);
|
||||
if (token != null && !token.isEmpty() && isValidJson(token)) {
|
||||
try {
|
||||
var response = objectMapper.readValue(token, ChatGPTResponseDetail.class);
|
||||
this.responseConsumer.accept(response.getDetail());
|
||||
} catch (JsonProcessingException e) {
|
||||
tryProcessingErrorResponse(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -67,4 +71,15 @@ public class ChatGPTBodySubscriber extends Subscriber<ChatGPTResponse> {
|
|||
future.completeExceptionally(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidJson(String json) {
|
||||
ObjectMapper mapper = new ObjectMapper()
|
||||
.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
|
||||
try {
|
||||
mapper.readTree(json);
|
||||
} catch (JacksonException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import com.intellij.openapi.actionSystem.AnAction;
|
|||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import ee.carlrobert.chatgpt.client.ClientFactory;
|
||||
import ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService;
|
||||
|
|
@ -11,26 +13,29 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
public abstract class BaseAction extends AnAction {
|
||||
|
||||
protected abstract String getPrompt(String selectedText);
|
||||
|
||||
protected abstract void initToolWindow(ToolWindow toolWindow);
|
||||
|
||||
protected abstract void actionPerformed(Project project, Editor editor, String selectedText);
|
||||
|
||||
public void actionPerformed(@NotNull AnActionEvent event) {
|
||||
var project = event.getProject();
|
||||
var editor = event.getData(PlatformDataKeys.EDITOR);
|
||||
if (editor != null && project != null) {
|
||||
var toolWindowService = ApplicationManager.getApplication().getService(ToolWindowService.class);
|
||||
var selectedText = editor.getSelectionModel().getSelectedText();
|
||||
new ClientFactory().getClient().clearPreviousSession();
|
||||
initToolWindow(toolWindowService.getToolWindow(project));
|
||||
toolWindowService.removeAll();
|
||||
toolWindowService.paintUserMessage(selectedText);
|
||||
toolWindowService.sendMessage(getPrompt(selectedText), project, null);
|
||||
actionPerformed(project, editor, editor.getSelectionModel().getSelectedText());
|
||||
}
|
||||
}
|
||||
|
||||
public void update(AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(e.getProject() != null);
|
||||
}
|
||||
|
||||
protected void sendMessage(Project project, String prompt) {
|
||||
var toolWindowService = ApplicationManager.getApplication().getService(ToolWindowService.class);
|
||||
new ClientFactory().getClient().clearPreviousSession();
|
||||
initToolWindow(toolWindowService.getToolWindow(project));
|
||||
toolWindowService.removeAll();
|
||||
toolWindowService.paintUserMessage(prompt);
|
||||
toolWindowService.sendMessage(prompt, project, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class CustomPromptAction extends BaseAction {
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Custom Prompt");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
if (selectedText != null && !selectedText.isEmpty()) {
|
||||
var fileExtension = getFileExtension(((EditorImpl) editor).getVirtualFile().getName());
|
||||
var dialog = new CustomPromptDialog(selectedText, fileExtension);
|
||||
if (dialog.showAndGet()) {
|
||||
SwingUtilities.invokeLater(() -> sendMessage(project, dialog.getPrompt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileExtension(String filename) {
|
||||
Pattern pattern = Pattern.compile("[^.]+$");
|
||||
Matcher matcher = pattern.matcher(filename);
|
||||
|
||||
if (matcher.find()) {
|
||||
return matcher.group();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UI;
|
||||
import ee.carlrobert.chatgpt.ide.toolwindow.components.SyntaxTextArea;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
|
||||
public class CustomPromptDialog extends DialogWrapper {
|
||||
|
||||
private final String selectedText;
|
||||
private final String fileExtension;
|
||||
private final JTextArea prefixTextArea = new JTextArea();
|
||||
private final SyntaxTextArea syntaxTextArea = new SyntaxTextArea(false, false, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
|
||||
public CustomPromptDialog(String selectedText, String fileExtension) {
|
||||
super(true);
|
||||
this.selectedText = selectedText;
|
||||
this.fileExtension = fileExtension;
|
||||
setTitle("Custom Prompt");
|
||||
setSize(460, 320);
|
||||
init();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
prefixTextArea.setLineWrap(true);
|
||||
prefixTextArea.setWrapStyleWord(true);
|
||||
prefixTextArea.setMargin(JBUI.insets(5));
|
||||
|
||||
syntaxTextArea.setText(selectedText.trim());
|
||||
// syntaxTextArea.setSyntaxEditingStyle(getSyntaxForFileExtension(fileExtension));
|
||||
syntaxTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
|
||||
return FormBuilder.createFormBuilder()
|
||||
.addComponent(UI.PanelFactory.panel(prefixTextArea)
|
||||
.withLabel("Prefix:")
|
||||
.moveLabelOnTop()
|
||||
.withComment(
|
||||
"Example: Find bugs in the following code")
|
||||
.createPanel())
|
||||
.addVerticalGap(16)
|
||||
.addComponent(new JBScrollPane(syntaxTextArea))
|
||||
.getPanel();
|
||||
}
|
||||
|
||||
public String getPrompt() {
|
||||
return prefixTextArea.getText() + "\n\n" + syntaxTextArea.getText();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
|
||||
public class ExplainAction extends BaseAction {
|
||||
|
||||
protected String getPrompt(String selectedText) {
|
||||
return "Explain the following code:\n" + selectedText;
|
||||
}
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Explain Code");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
sendMessage(project, "Explain the following code:\n\n" + selectedText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
|
||||
public class FindBugsAction extends BaseAction {
|
||||
|
||||
protected String getPrompt(String selectedText) {
|
||||
return "Find bugs in the following code:\n" + selectedText;
|
||||
}
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Find Bugs");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
sendMessage(project, "Find bugs in the following code:\n\n" + selectedText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
|
||||
public class OptimizeAction extends BaseAction {
|
||||
|
||||
protected String getPrompt(String selectedText) {
|
||||
return "Optimize the following code:\n" + selectedText;
|
||||
}
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Optimize Code");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
sendMessage(project, "Optimize the following code:\n\n" + selectedText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
|
||||
public class RefactorAction extends BaseAction {
|
||||
|
||||
protected String getPrompt(String selectedText) {
|
||||
return "Refactor the following code:\n" + selectedText;
|
||||
}
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Refactor Code");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
sendMessage(project, "Refactor the following code:\n\n" + selectedText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
package ee.carlrobert.chatgpt.ide.action;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.wm.ToolWindow;
|
||||
|
||||
public class WriteTestsAction extends BaseAction {
|
||||
|
||||
protected String getPrompt(String selectedText) {
|
||||
return "Generate unit tests for the following code:\n" + selectedText;
|
||||
}
|
||||
|
||||
protected void initToolWindow(ToolWindow toolWindow) {
|
||||
toolWindow.setTitle("Write Tests");
|
||||
toolWindow.show();
|
||||
}
|
||||
|
||||
protected void actionPerformed(Project project, Editor editor, String selectedText) {
|
||||
sendMessage(project, "Generate unit tests for the following code:\n\n" + selectedText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ import javax.swing.ImageIcon;
|
|||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ToolWindowService implements LafManagerListener {
|
||||
|
|
@ -65,20 +67,21 @@ public class ToolWindowService implements LafManagerListener {
|
|||
} else if (settings.isChatGPTOptionSelected && settings.accessToken.isEmpty()) {
|
||||
notifyMissingCredential(project, "Access token not provided.");
|
||||
} else {
|
||||
var textArea = new SyntaxTextArea();
|
||||
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
scrollablePanel.add(textArea);
|
||||
textAreas.add(textArea);
|
||||
|
||||
var client = new ClientFactory().getClient();
|
||||
client.getCompletionsAsync(prompt, message -> {
|
||||
textArea.append(message);
|
||||
|
||||
if (scrollToBottom != null) {
|
||||
scrollToBottom.run();
|
||||
}
|
||||
}, () -> {
|
||||
client.getCompletionsAsync(prompt, message -> SwingUtilities.invokeLater(
|
||||
() -> {
|
||||
textArea.append(message);
|
||||
if (scrollToBottom != null) {
|
||||
scrollToBottom.run();
|
||||
}
|
||||
}
|
||||
), () -> {
|
||||
textArea.displayCopyButton();
|
||||
textArea.enableSelection();
|
||||
textArea.hideCaret();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ import java.awt.datatransfer.StringSelection;
|
|||
import java.io.IOException;
|
||||
import javax.swing.JButton;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||
import org.fife.ui.rtextarea.CaretStyle;
|
||||
|
||||
public class SyntaxTextArea extends RSyntaxTextArea {
|
||||
|
||||
public SyntaxTextArea() {
|
||||
public SyntaxTextArea(boolean isReadOnly, boolean withBlockCaret, String syntax) {
|
||||
super("");
|
||||
setStyles();
|
||||
setStyles(isReadOnly, withBlockCaret, syntax);
|
||||
}
|
||||
|
||||
public void displayCopyButton() {
|
||||
|
|
@ -27,9 +27,8 @@ public class SyntaxTextArea extends RSyntaxTextArea {
|
|||
cb.install(this);
|
||||
}
|
||||
|
||||
public void enableSelection() {
|
||||
setEditable(false);
|
||||
setEnabled(true);
|
||||
public void hideCaret() {
|
||||
getCaret().setVisible(false);
|
||||
}
|
||||
|
||||
public void changeStyleViaThemeXml() {
|
||||
|
|
@ -43,20 +42,24 @@ public class SyntaxTextArea extends RSyntaxTextArea {
|
|||
}
|
||||
}
|
||||
|
||||
private void setStyles() {
|
||||
private void setStyles(boolean isReadOnly, boolean withBlockCaret, String syntax) {
|
||||
setMargin(JBUI.insets(5));
|
||||
setAntiAliasingEnabled(true);
|
||||
setEnabled(false);
|
||||
setEnabled(true);
|
||||
setEditable(!isReadOnly);
|
||||
setPaintTabLines(false);
|
||||
setHighlightCurrentLine(false);
|
||||
setLineWrap(true);
|
||||
setWrapStyleWord(true);
|
||||
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
|
||||
if (withBlockCaret) {
|
||||
setCaretStyle(0, CaretStyle.BLOCK_STYLE);
|
||||
getCaret().setVisible(true);
|
||||
}
|
||||
setSyntaxEditingStyle(syntax);
|
||||
changeStyleViaThemeXml();
|
||||
}
|
||||
|
||||
private void copyToClipboard() {
|
||||
StringSelection stringSelection = new StringSelection(getText());
|
||||
StringSelection stringSelection = new StringSelection(getText().trim());
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
clipboard.setContents(stringSelection, null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue