Change project's name, heavy refactoring

This commit is contained in:
Carl-Robert Linnupuu 2023-03-12 20:56:44 +00:00
parent c0cea7cc43
commit 483abe146b
80 changed files with 969 additions and 968 deletions

View file

@ -1 +1 @@
rootProject.name = "ChatGPT"
rootProject.name = "CodeGPT"

View file

@ -1,39 +0,0 @@
package ee.carlrobert.chatgpt.client.official;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseError {
private Error error;
public Error getError() {
return error;
}
public void setError(Error error) {
this.error = error;
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class Error {
private String message;
private String type;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}

View file

@ -1,28 +0,0 @@
package ee.carlrobert.chatgpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import ee.carlrobert.chatgpt.client.BaseApiResponse;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponse implements BaseApiResponse {
private String id;
private List<ApiResponseChoice> choices;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<ApiResponseChoice> getChoices() {
return choices;
}
public void setChoices(List<ApiResponseChoice> choices) {
this.choices = choices;
}
}

View file

@ -1,17 +0,0 @@
package ee.carlrobert.chatgpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseChoice {
private ApiResponseChoiceDelta delta;
public ApiResponseChoiceDelta getDelta() {
return delta;
}
public void setDelta(ApiResponseChoiceDelta delta) {
this.delta = delta;
}
}

View file

@ -1,26 +0,0 @@
package ee.carlrobert.chatgpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseChoiceDelta {
private String role;
private String content;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View file

@ -1,28 +0,0 @@
package ee.carlrobert.chatgpt.client.official.text.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import ee.carlrobert.chatgpt.client.BaseApiResponse;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponse implements BaseApiResponse {
private String id;
private List<ApiResponseChoice> choices;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<ApiResponseChoice> getChoices() {
return choices;
}
public void setChoices(List<ApiResponseChoice> choices) {
this.choices = choices;
}
}

View file

@ -1,17 +0,0 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseDetail {
private String detail;
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
}

View file

@ -1,17 +0,0 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseError {
private ApiResponseErrorDetails detail;
public ApiResponseErrorDetails getDetail() {
return detail;
}
public void setDetail(ApiResponseErrorDetails detail) {
this.detail = detail;
}
}

View file

@ -1,35 +0,0 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseErrorDetails {
private String message;
private String type;
private String code;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View file

@ -1,35 +0,0 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseMessage {
private String id;
private ApiResponseMessageAuthor author;
private ApiResponseMessageContent content;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public ApiResponseMessageAuthor getAuthor() {
return author;
}
public void setAuthor(ApiResponseMessageAuthor author) {
this.author = author;
}
public ApiResponseMessageContent getContent() {
return content;
}
public void setContent(ApiResponseMessageContent content) {
this.content = content;
}
}

View file

@ -1,17 +0,0 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseMessageAuthor {
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}

View file

@ -1,13 +0,0 @@
package ee.carlrobert.chatgpt.ide.action;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import icons.Icons;
public class ActionGroup extends DefaultActionGroup {
@Override
public void update(AnActionEvent event) {
event.getPresentation().setIcon(Icons.DefaultIcon);
}
}

View file

@ -1,42 +0,0 @@
package ee.carlrobert.chatgpt.ide.action;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService;
import java.util.Arrays;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
public class AskAction extends AnAction {
@Override
public void update(@NotNull AnActionEvent event) {
event.getPresentation().setEnabled(event.getProject() != null);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
if (project != null) {
var toolWindowService = project.getService(ToolWindowService.class);
var toolWindow = toolWindowService.getToolWindow(project);
var contentManager = toolWindow.getContentManager();
Arrays.stream(contentManager.getContents())
.filter(it -> "Chat".equals(it.getTabName()))
.findFirst()
.ifPresentOrElse(
contentManager::setSelectedContent,
() -> contentManager.setSelectedContent(Objects.requireNonNull(contentManager.getContent(0)))
);
ConversationsState.getInstance().startConversation();
toolWindow.show();
toolWindow.setTitle("Chat");
toolWindowService.removeAll();
toolWindowService.paintLandingView();
}
}
}

View file

@ -1,23 +0,0 @@
package ee.carlrobert.chatgpt.ide.conversations.message;
public class Message {
private String prompt;
private String response;
public String getPrompt() {
return prompt;
}
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}

View file

@ -1,96 +0,0 @@
package ee.carlrobert.chatgpt.ide.toolwindow;
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 com.intellij.util.ui.JBUI;
import ee.carlrobert.chatgpt.ide.toolwindow.components.GenerateButton;
import ee.carlrobert.chatgpt.ide.toolwindow.components.TextArea;
import java.awt.Adjustable;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import org.jetbrains.annotations.NotNull;
public class ChatGptToolWindow {
private final Project project;
private JPanel chatGptToolWindowContent;
private JScrollPane scrollPane;
private JTextArea textArea;
private JScrollPane textAreaScrollPane;
private JButton generateButton;
public ChatGptToolWindow(@NotNull Project project) {
this.project = project;
}
public void handleSubmit() {
var toolWindowService = project.getService(ToolWindowService.class);
var searchText = textArea.getText();
toolWindowService.paintUserMessage(searchText);
toolWindowService.sendMessage(searchText, project, this::scrollToBottom);
textArea.setText("");
scrollToBottom();
}
public JPanel getContent() {
return chatGptToolWindowContent;
}
private void scrollToBottom() {
JScrollBar verticalBar = this.scrollPane.getVerticalScrollBar();
verticalBar.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
Adjustable adjustable = e.getAdjustable();
adjustable.setValue(adjustable.getMaximum());
verticalBar.removeAdjustmentListener(this);
}
});
}
private void createUIComponents() {
textAreaScrollPane = new JBScrollPane() {
@Override
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)));
textAreaScrollPane.setViewportView(textArea);
textArea = new TextArea(this::handleSubmit, textAreaScrollPane);
ScrollablePanel scrollablePanel = new ScrollablePanel();
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
scrollPane = new JBScrollPane();
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setViewportView(scrollablePanel);
scrollPane.setBorder(JBUI.Borders.empty(0, 8));
scrollPane.setViewportBorder(null);
generateButton = new GenerateButton();
var toolWindowService = project.getService(ToolWindowService.class);
toolWindowService.setGenerateButton((GenerateButton) generateButton); // TODO: Remove casting
toolWindowService.setScrollPane(scrollPane);
toolWindowService.setScrollablePanel(scrollablePanel);
toolWindowService.paintLandingView();
}
}

View file

@ -1,54 +0,0 @@
package ee.carlrobert.chatgpt.ide.toolwindow;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.content.ContentManagerListener;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.toolwindow.conversations.ConversationsToolWindow;
import java.util.Arrays;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
public class ChatGptToolWindowFactory implements ToolWindowFactory, DumbAware {
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
addContent(toolWindow, new ChatGptToolWindow(project).getContent(), "Chat");
var conversationToolWidow = new ConversationsToolWindow(project, toolWindow);
addContent(toolWindow, conversationToolWidow.getContent(), "Conversation History");
toolWindow.addContentManagerListener(new ContentManagerListener() {
public void selectionChanged(@NotNull ContentManagerEvent event) {
if ("Conversation History".equals(event.getContent().getTabName()) && event.getContent().isSelected()) {
conversationToolWidow.refresh();
}
}
});
var conversation = ConversationsState.getCurrentConversation();
if (conversation != null) {
var toolWindowService = project.getService(ToolWindowService.class);
var contentManager = toolWindow.getContentManager();
Arrays.stream(contentManager.getContents())
.filter(content -> "Chat".equals(content.getTabName()))
.findFirst()
.ifPresent(
content -> {
if (contentManager.isSelected(content)) {
toolWindowService.displayConversation(conversation);
}
}
);
}
}
private void addContent(@NotNull ToolWindow toolWindow, JPanel content, String displayName) {
toolWindow.getContentManager().addContent(ApplicationManager.getApplication()
.getService(ContentFactory.class)
.createContent(content, displayName, false));
}
}

View file

@ -1,244 +0,0 @@
package ee.carlrobert.chatgpt.ide.toolwindow;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.createIconLabel;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.createTextArea;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.justifyLeft;
import static java.lang.String.format;
import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.LafManager;
import com.intellij.ide.ui.LafManagerListener;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import ee.carlrobert.chatgpt.client.ClientFactory;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.conversations.message.Message;
import ee.carlrobert.chatgpt.ide.settings.SettingsConfigurable;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.chatgpt.ide.toolwindow.components.GenerateButton;
import ee.carlrobert.chatgpt.ide.toolwindow.components.GenerateButton.Mode;
import ee.carlrobert.chatgpt.ide.toolwindow.components.SyntaxTextArea;
import icons.Icons;
import java.awt.Adjustable;
import java.awt.Cursor;
import java.awt.GridBagLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.jetbrains.annotations.NotNull;
public class ToolWindowService implements LafManagerListener {
private static final List<SyntaxTextArea> textAreas = new ArrayList<>();
private boolean isLandingViewVisible;
private ScrollablePanel scrollablePanel;
private JScrollPane scrollPane;
private GenerateButton generateButton;
public void setScrollablePanel(ScrollablePanel scrollablePanel) {
this.scrollablePanel = scrollablePanel;
}
public void setScrollPane(JScrollPane scrollPane) {
this.scrollPane = scrollPane;
}
public void setGenerateButton(GenerateButton generateButton) {
this.generateButton = generateButton;
}
@Override
public void lookAndFeelChanged(@NotNull LafManager source) {
for (var textArea : textAreas) {
textArea.changeStyleViaThemeXml();
}
}
public ToolWindow getToolWindow(@NotNull Project project) {
return ToolWindowManager.getInstance(project).getToolWindow("CodeGPT");
}
public void paintUserMessage(String userMessage) {
if (isLandingViewVisible || ConversationsState.getCurrentConversation() == null) {
removeAll();
}
addSpacing(8);
addIconLabel(AllIcons.General.User, "User:");
addSpacing(8);
scrollablePanel.add(createTextArea(userMessage));
}
public void sendMessage(String prompt, Project project, @Nullable Runnable scrollToBottom) {
addSpacing(8);
addIconLabel(Icons.DefaultImageIcon, "ChatGPT:");
addSpacing(8);
var settings = SettingsState.getInstance();
if (settings.isGPTOptionSelected && settings.apiKey.isEmpty()) {
notifyMissingCredential(project, "API key not provided.");
} else if (settings.isChatGPTOptionSelected && settings.accessToken.isEmpty()) {
notifyMissingCredential(project, "Access token not provided.");
} else {
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
scrollablePanel.add(textArea);
textAreas.add(textArea);
var client = new ClientFactory().getClient();
generateButton.setVisible(true);
generateButton.setMode(Mode.STOP, client::cancelRequest);
var conversationMessage = new Message();
conversationMessage.setPrompt(prompt);
new SwingWorker<Void, String>() {
protected Void doInBackground() {
client.getCompletionsAsync(
prompt,
this::publish,
(completedConversation) -> {
ConversationsState.getInstance().saveConversation(completedConversation);
stopGenerating(prompt, textArea, project, scrollToBottom);
},
(errorMessage) -> {
var currentConversation = ConversationsState.getCurrentConversation();
if (currentConversation != null) {
conversationMessage.setResponse(errorMessage);
currentConversation.addMessage(conversationMessage);
ConversationsState.getInstance().saveConversation(currentConversation);
}
textArea.append(errorMessage);
stopGenerating(prompt, textArea, project, scrollToBottom);
});
return null;
}
protected void process(List<String> chunks) {
for (String text : chunks) {
try {
textArea.append(text);
conversationMessage.setResponse(textArea.getText());
if (scrollToBottom != null) {
scrollToBottom.run();
}
} catch (Exception e) {
textArea.append("Something went wrong. Please try again later.");
throw new RuntimeException(e);
}
}
}
}.execute();
}
}
public void displayConversation(Conversation conversation) {
removeAll();
conversation.getMessages().forEach(message -> {
paintUserMessage(message.getPrompt());
addSpacing(8);
addIconLabel(Icons.DefaultImageIcon, "ChatGPT:");
addSpacing(8);
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
textArea.setText(message.getResponse());
textArea.displayCopyButton();
textArea.hideCaret();
scrollablePanel.add(textArea);
textAreas.add(textArea);
});
scrollToBottom();
}
public void paintLandingView() {
isLandingViewVisible = true;
var imageIconPanel = new JPanel();
imageIconPanel.setLayout(new GridBagLayout());
var imageIconLabel = new JLabel(Icons.SunImageIcon);
imageIconLabel.setHorizontalAlignment(JLabel.CENTER);
imageIconPanel.add(imageIconLabel);
scrollablePanel.add(imageIconPanel);
addSpacing(16);
var questions = List.of("How do I make an HTTP request in Javascript?",
"What is the difference between px, dip, dp, and sp?",
"How do I undo the most recent local commits in Git?",
"What is the difference between stack and heap?");
for (var question : questions) {
var panel = new JPanel();
panel.setLayout(new GridBagLayout());
var label = new JLabel(question, SwingConstants.CENTER);
label.setHorizontalAlignment(JLabel.CENTER);
panel.add(label);
scrollablePanel.add(panel);
addSpacing(16);
}
}
public void removeAll() {
isLandingViewVisible = false;
generateButton.setVisible(false);
scrollablePanel.removeAll();
}
private void stopGenerating(String prompt, SyntaxTextArea textArea, Project project, @Nullable Runnable scrollToBottom) {
generateButton.setMode(Mode.REFRESH, () -> {
sendMessage(prompt, project, scrollToBottom);
if (scrollToBottom != null) {
scrollToBottom.run();
}
});
textArea.displayCopyButton();
textArea.hideCaret();
if (scrollToBottom != null) {
scrollToBottom.run();
}
}
private void addSpacing(int height) {
scrollablePanel.add(Box.createVerticalStrut(height));
}
private void addIconLabel(Icon icon, String text) {
scrollablePanel.add(justifyLeft(createIconLabel(icon, text)));
}
private 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));
}
private void scrollToBottom() {
JScrollBar verticalBar = scrollPane.getVerticalScrollBar();
verticalBar.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
Adjustable adjustable = e.getAdjustable();
adjustable.setValue(adjustable.getMaximum());
verticalBar.removeAdjustmentListener(this);
}
});
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
public class ApiRequestDetails {

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
public interface BaseApiResponse {
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
public enum BaseModel {

View file

@ -1,11 +1,10 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Map;
@ -73,12 +72,11 @@ public abstract class Client {
var username = settings.proxyUsername;
var password = settings.proxyPassword;
if (settings.isProxyAuthSelected) {
builder.proxyAuthenticator((route, response) -> {
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
});
builder.proxyAuthenticator((route, response) ->
response.request()
.newBuilder()
.header("Proxy-Authorization", Credentials.basic(username, password))
.build());
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
public enum ClientCode {

View file

@ -1,9 +1,9 @@
package ee.carlrobert.chatgpt.client;
package ee.carlrobert.codegpt.client;
import ee.carlrobert.chatgpt.client.unofficial.UnofficialChatGPTClient;
import ee.carlrobert.chatgpt.client.official.chat.ChatCompletionClient;
import ee.carlrobert.chatgpt.client.official.text.TextCompletionClient;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.client.unofficial.UnofficialChatGPTClient;
import ee.carlrobert.codegpt.client.official.chat.ChatCompletionClient;
import ee.carlrobert.codegpt.client.official.text.TextCompletionClient;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
public class ClientFactory {

View file

@ -0,0 +1,40 @@
package ee.carlrobert.codegpt.client.official;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseError {
private final ErrorDetails error;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseError(@JsonProperty("error") ErrorDetails error) {
this.error = error;
}
public ErrorDetails getError() {
return error;
}
@JsonIgnoreProperties(ignoreUnknown = true)
static class ErrorDetails {
private final String message;
private final String type;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ErrorDetails(@JsonProperty("message") String message, @JsonProperty("type") String type) {
this.message = message;
this.type = type;
}
public String getMessage() {
return message;
}
public String getType() {
return type;
}
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client.official;
package ee.carlrobert.codegpt.client.official;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

View file

@ -1,13 +1,13 @@
package ee.carlrobert.chatgpt.client.official.chat;
package ee.carlrobert.codegpt.client.official.chat;
import ee.carlrobert.chatgpt.client.ApiRequestDetails;
import ee.carlrobert.chatgpt.client.Client;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.chatgpt.client.official.chat.request.ApiRequest;
import ee.carlrobert.chatgpt.client.official.chat.request.ApiRequestMessage;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.message.Message;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.client.ApiRequestDetails;
import ee.carlrobert.codegpt.client.Client;
import ee.carlrobert.codegpt.client.ClientCode;
import ee.carlrobert.codegpt.client.official.chat.request.ApiRequest;
import ee.carlrobert.codegpt.client.official.chat.request.ApiRequestMessage;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.message.Message;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.function.Consumer;
@ -54,8 +54,7 @@ public class ChatCompletionClient extends Client {
Consumer<Conversation> onComplete,
Consumer<String> onFailure) {
return new ChatCompletionClientEventListener(client, onMessageReceived, finalMessage -> {
var message = new Message();
message.setPrompt(prompt);
var message = new Message(prompt);
message.setResponse(finalMessage);
conversation.setUpdatedOn(LocalDateTime.now());
conversation.addMessage(message);

View file

@ -1,9 +1,9 @@
package ee.carlrobert.chatgpt.client.official.chat;
package ee.carlrobert.codegpt.client.official.chat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ee.carlrobert.chatgpt.client.official.CompletionClientEventListener;
import ee.carlrobert.chatgpt.client.official.chat.response.ApiResponse;
import ee.carlrobert.codegpt.client.official.CompletionClientEventListener;
import ee.carlrobert.codegpt.client.official.chat.response.ApiResponse;
import java.util.function.Consumer;
import okhttp3.OkHttpClient;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client.official.chat.request;
package ee.carlrobert.codegpt.client.official.chat.request;
import java.util.List;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.client.official.chat.request;
package ee.carlrobert.codegpt.client.official.chat.request;
public class ApiRequestMessage {

View file

@ -0,0 +1,30 @@
package ee.carlrobert.codegpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ee.carlrobert.codegpt.client.BaseApiResponse;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponse implements BaseApiResponse {
private final String id;
private final List<ApiResponseChoice> choices;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponse(
@JsonProperty("id") String id,
@JsonProperty("choices") List<ApiResponseChoice> choices) {
this.id = id;
this.choices = choices;
}
public String getId() {
return id;
}
public List<ApiResponseChoice> getChoices() {
return choices;
}
}

View file

@ -0,0 +1,20 @@
package ee.carlrobert.codegpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseChoice {
private final ApiResponseChoiceDelta delta;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseChoice(@JsonProperty("delta") ApiResponseChoiceDelta delta) {
this.delta = delta;
}
public ApiResponseChoiceDelta getDelta() {
return delta;
}
}

View file

@ -0,0 +1,28 @@
package ee.carlrobert.codegpt.client.official.chat.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseChoiceDelta {
private final String role;
private final String content;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseChoiceDelta(
@JsonProperty("role") String role,
@JsonProperty("content") String content) {
this.role = role;
this.content = content;
}
public String getRole() {
return role;
}
public String getContent() {
return content;
}
}

View file

@ -1,14 +1,14 @@
package ee.carlrobert.chatgpt.client.official.text;
package ee.carlrobert.codegpt.client.official.text;
import static java.lang.String.format;
import ee.carlrobert.chatgpt.client.ApiRequestDetails;
import ee.carlrobert.chatgpt.client.BaseModel;
import ee.carlrobert.chatgpt.client.Client;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.message.Message;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.client.ApiRequestDetails;
import ee.carlrobert.codegpt.client.BaseModel;
import ee.carlrobert.codegpt.client.Client;
import ee.carlrobert.codegpt.client.ClientCode;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.message.Message;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@ -53,11 +53,8 @@ public class TextCompletionClient extends Client {
Consumer<Conversation> onComplete,
Consumer<String> onFailure) {
return new TextCompletionClientEventListener(client, onMessageReceived, (finalMessage) -> {
var message = new Message();
message.setPrompt(prompt);
message.setResponse(finalMessage);
conversation.setUpdatedOn(LocalDateTime.now());
conversation.addMessage(message);
conversation.addMessage(new Message(prompt, finalMessage));
onComplete.accept(conversation);
}, onFailure);
}

View file

@ -1,9 +1,9 @@
package ee.carlrobert.chatgpt.client.official.text;
package ee.carlrobert.codegpt.client.official.text;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ee.carlrobert.chatgpt.client.official.CompletionClientEventListener;
import ee.carlrobert.chatgpt.client.official.text.response.ApiResponse;
import ee.carlrobert.codegpt.client.official.CompletionClientEventListener;
import ee.carlrobert.codegpt.client.official.text.response.ApiResponse;
import java.util.function.Consumer;
import okhttp3.OkHttpClient;

View file

@ -0,0 +1,31 @@
package ee.carlrobert.codegpt.client.official.text.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ee.carlrobert.codegpt.client.BaseApiResponse;
import java.util.List;
// TODO: BaseCompletionApiResponse / CompletionApiResponse
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponse implements BaseApiResponse {
private final String id;
private final List<ApiResponseChoice> choices;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponse(
@JsonProperty("id") String id,
@JsonProperty("choices") List<ApiResponseChoice> choices) {
this.id = id;
this.choices = choices;
}
public String getId() {
return id;
}
public List<ApiResponseChoice> getChoices() {
return choices;
}
}

View file

@ -1,28 +1,28 @@
package ee.carlrobert.chatgpt.client.official.text.response;
package ee.carlrobert.codegpt.client.official.text.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseChoice {
private String text;
@JsonProperty("finish_reason")
private String finishReason;
private final String text;
private final String finishReason;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseChoice(
@JsonProperty("text") String text,
@JsonProperty("finish_reason") String finishReason) {
this.text = text;
this.finishReason = finishReason;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getFinishReason() {
return finishReason;
}
public void setFinishReason(String finishReason) {
this.finishReason = finishReason;
}
}

View file

@ -1,11 +1,11 @@
package ee.carlrobert.chatgpt.client.unofficial;
package ee.carlrobert.codegpt.client.unofficial;
import ee.carlrobert.chatgpt.client.ApiRequestDetails;
import ee.carlrobert.chatgpt.client.Client;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.message.Message;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.client.ApiRequestDetails;
import ee.carlrobert.codegpt.client.Client;
import ee.carlrobert.codegpt.client.ClientCode;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.message.Message;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
@ -34,8 +34,7 @@ public class UnofficialChatGPTClient extends Client {
Consumer<Conversation> onComplete,
Consumer<String> onFailure) {
return new UnofficialClientEventListener(client, prompt, onMessageReceived, (response) -> {
var message = new Message();
message.setPrompt(prompt);
var message = new Message(prompt);
message.setResponse(response.getFullMessage());
conversation.setUnofficialClientConversationId(response.getConversationId());

View file

@ -1,10 +1,10 @@
package ee.carlrobert.chatgpt.client.unofficial;
package ee.carlrobert.codegpt.client.unofficial;
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.unofficial.response.ApiResponse;
import ee.carlrobert.codegpt.client.unofficial.response.ApiResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
@ -13,13 +13,16 @@ import javax.annotation.Nullable;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UnofficialClientEventListener extends EventSourceListener {
private static final Logger LOG = LoggerFactory.getLogger(UnofficialClientEventListener.class);
private final ObjectMapper objectMapper = new ObjectMapper();
private final String prompt;
private final Consumer<String> onMessageReceived;
@ -47,14 +50,12 @@ public class UnofficialClientEventListener extends EventSourceListener {
public void onClosed(@NotNull EventSource eventSource) {
if (!eventReceived) {
var client = UnofficialChatGPTClient.getInstance().buildClient();
var clientInstance = UnofficialChatGPTClient.getInstance();
try {
var response = client.newCall(UnofficialChatGPTClient.getInstance().buildHttpRequest(prompt)).execute();
ResponseBody responseBody = response.body();
if (responseBody != null) {
tryExtractingErrorMessage(responseBody.string()).ifPresent(onFailure);
responseBody.close();
}
var response = clientInstance.buildClient()
.newCall(clientInstance.buildHttpRequest(prompt))
.execute();
tryExtractingErrorResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -97,11 +98,7 @@ public class UnofficialClientEventListener extends EventSourceListener {
@Nullable Response response) {
if (isRequestNotCancelled() && response != null) {
try {
var responseBody = response.body();
if (responseBody != null) {
tryExtractingErrorMessage(responseBody.string()).ifPresent(onFailure);
responseBody.close();
}
tryExtractingErrorResponse(response);
} catch (Exception e) {
onFailure.accept("Something went wrong. Please try again later.");
}
@ -114,6 +111,18 @@ public class UnofficialClientEventListener extends EventSourceListener {
return client.dispatcher().runningCalls().stream().noneMatch(Call::isCanceled);
}
private void tryExtractingErrorResponse(Response response) {
try (response) {
var responseBody = response.body();
if (responseBody != null) {
tryExtractingErrorMessage(responseBody.string()).ifPresent(onFailure);
responseBody.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Optional<String> tryExtractingErrorMessage(String jsonPayload) {
try {
var error = objectMapper.readValue(jsonPayload, Map.class);

View file

@ -1,32 +1,32 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
package ee.carlrobert.codegpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ee.carlrobert.chatgpt.client.BaseApiResponse;
import ee.carlrobert.codegpt.client.BaseApiResponse;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponse implements BaseApiResponse {
private ApiResponseMessage message;
@JsonProperty("conversation_id")
private String conversationId;
private final ApiResponseMessage message;
private final String conversationId;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponse(
@JsonProperty("message") ApiResponseMessage message,
@JsonProperty("conversation_id") String conversationId) {
this.message = message;
this.conversationId = conversationId;
}
public ApiResponseMessage getMessage() {
return message;
}
public void setMessage(ApiResponseMessage message) {
this.message = message;
}
public String getConversationId() {
return conversationId;
}
public void setConversationId(String conversationId) {
this.conversationId = conversationId;
}
public String getFullMessage() {
return String.join("", message.getContent().getParts());
}

View file

@ -0,0 +1,35 @@
package ee.carlrobert.codegpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseMessage {
private final String id;
private final ApiResponseMessageAuthor author;
private final ApiResponseMessageContent content;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseMessage(
@JsonProperty("id") String id,
@JsonProperty("author") ApiResponseMessageAuthor author,
@JsonProperty("content") ApiResponseMessageContent content) {
this.id = id;
this.author = author;
this.content = content;
}
public String getId() {
return id;
}
public ApiResponseMessageAuthor getAuthor() {
return author;
}
public ApiResponseMessageContent getContent() {
return content;
}
}

View file

@ -0,0 +1,20 @@
package ee.carlrobert.codegpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseMessageAuthor {
private final String role;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseMessageAuthor(@JsonProperty("role") String role) {
this.role = role;
}
public String getRole() {
return role;
}
}

View file

@ -1,29 +1,26 @@
package ee.carlrobert.chatgpt.client.unofficial.response;
package ee.carlrobert.codegpt.client.unofficial.response;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiResponseMessageContent {
@JsonProperty("content_type")
private String contentType;
private List<String> parts;
private final String contentType;
private final List<String> parts;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public ApiResponseMessageContent(String contentType, List<String> parts) {
this.contentType = contentType;
this.parts = parts;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public List<String> getParts() {
return parts;
}
public void setParts(List<String> parts) {
this.parts = parts;
}
}

View file

@ -0,0 +1,30 @@
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService;
import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService;
import org.jetbrains.annotations.NotNull;
public class AskAction extends AnAction {
@Override
public void update(@NotNull AnActionEvent event) {
event.getPresentation().setEnabled(event.getProject() != null);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
if (project != null) {
ConversationsState.getInstance().startConversation();
ContentManagerService.getInstance(project).displayChatTab();
var chatToolWindow = project.getService(ToolWindowService.class).getChatToolWindow();
chatToolWindow.show();
chatToolWindow.clearWindow();
chatToolWindow.displayLandingView();
}
}
}

View file

@ -1,14 +1,13 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService;
import java.util.Arrays;
import java.util.Objects;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService;
import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService;
import org.jetbrains.annotations.NotNull;
public abstract class BaseAction extends AnAction {
@ -33,25 +32,15 @@ public abstract class BaseAction extends AnAction {
event.getPresentation().setEnabled(menuAllowed);
}
protected void sendMessage(Project project, String prompt) {
var toolWindowService = project.getService(ToolWindowService.class);
var toolWindow = toolWindowService.getToolWindow(project);
var contentManager = toolWindow.getContentManager();
Arrays.stream(contentManager.getContents())
.filter(it -> "Chat".equals(it.getTabName()))
.findFirst()
.ifPresentOrElse(
contentManager::setSelectedContent,
() -> contentManager.setSelectedContent(Objects.requireNonNull(contentManager.getContent(0)))
);
protected void sendMessage(@NotNull Project project, String prompt) {
ConversationsState.getInstance().startConversation();
ContentManagerService.getInstance(project).displayChatTab();
toolWindowService.getToolWindow(project).show();
toolWindowService.removeAll();
toolWindowService.paintUserMessage(prompt);
toolWindowService.sendMessage(prompt, project, null);
var toolWindowService = project.getService(ToolWindowService.class);
var chatToolWindow = toolWindowService.getChatToolWindow();
chatToolWindow.show();
chatToolWindow.clearWindow();
chatToolWindow.displayUserMessage(prompt);
toolWindowService.sendMessage(prompt, project);
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.impl.EditorImpl;

View file

@ -1,13 +1,13 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.addShiftEnterInputMap;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.addShiftEnterInputMap;
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 ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea;
import javax.annotation.Nullable;
import javax.swing.JComponent;
import javax.swing.JTextArea;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.action;
package ee.carlrobert.codegpt.ide.action;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;

View file

@ -1,8 +1,8 @@
package ee.carlrobert.chatgpt.ide.conversations;
package ee.carlrobert.codegpt.ide.conversations;
import ee.carlrobert.chatgpt.client.BaseModel;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.chatgpt.ide.conversations.message.Message;
import ee.carlrobert.codegpt.client.BaseModel;
import ee.carlrobert.codegpt.client.ClientCode;
import ee.carlrobert.codegpt.ide.conversations.message.Message;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

View file

@ -1,6 +1,6 @@
package ee.carlrobert.chatgpt.ide.conversations;
package ee.carlrobert.codegpt.ide.conversations;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.codegpt.client.ClientCode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.conversations;
package ee.carlrobert.codegpt.ide.conversations;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
@ -6,11 +6,11 @@ import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import com.intellij.util.xmlb.annotations.OptionTag;
import ee.carlrobert.chatgpt.client.ClientCode;
import ee.carlrobert.chatgpt.client.ClientFactory;
import ee.carlrobert.chatgpt.ide.conversations.converter.ConversationConverter;
import ee.carlrobert.chatgpt.ide.conversations.converter.ConversationsConverter;
import ee.carlrobert.chatgpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.client.ClientCode;
import ee.carlrobert.codegpt.client.ClientFactory;
import ee.carlrobert.codegpt.ide.conversations.converter.ConversationConverter;
import ee.carlrobert.codegpt.ide.conversations.converter.ConversationsConverter;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.UUID;
@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(
name = "ee.carlrobert.chatgpt.ide.conversations.ConversationsState",
name = "ee.carlrobert.codegpt.ide.conversations.ConversationsState",
storages = @Storage("ChatGPTConversations.xml")
)
public class ConversationsState implements PersistentStateComponent<ConversationsState> {

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.conversations.converter;
package ee.carlrobert.codegpt.ide.conversations.converter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

View file

@ -1,6 +1,6 @@
package ee.carlrobert.chatgpt.ide.conversations.converter;
package ee.carlrobert.codegpt.ide.conversations.converter;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
public class ConversationConverter extends BaseConverter<Conversation> {

View file

@ -1,6 +1,6 @@
package ee.carlrobert.chatgpt.ide.conversations.converter;
package ee.carlrobert.codegpt.ide.conversations.converter;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsContainer;
import ee.carlrobert.codegpt.ide.conversations.ConversationsContainer;
public class ConversationsConverter extends BaseConverter<ConversationsContainer> {

View file

@ -0,0 +1,32 @@
package ee.carlrobert.codegpt.ide.conversations.message;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Message {
private final String prompt;
private String response;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public Message(@JsonProperty("prompt") String prompt) {
this.prompt = prompt;
}
public Message(String prompt, String response) {
this.prompt = prompt;
this.response = response;
}
public String getPrompt() {
return prompt;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}

View file

@ -1,7 +1,7 @@
package ee.carlrobert.chatgpt.ide.settings;
package ee.carlrobert.codegpt.ide.settings;
import com.intellij.openapi.ui.ComboBox;
import ee.carlrobert.chatgpt.client.BaseModel;
import ee.carlrobert.codegpt.client.BaseModel;
import java.awt.Component;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
@ -16,14 +16,8 @@ public class BaseModelComboBox extends ComboBox<BaseModel> {
private BasicComboBoxRenderer getBasicComboBoxRenderer() {
return new BasicComboBoxRenderer() {
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
BaseModel model = (BaseModel) value;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.settings;
package ee.carlrobert.codegpt.ide.settings;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.PortField;
@ -10,7 +10,7 @@ import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UI;
import ee.carlrobert.chatgpt.client.BaseModel;
import ee.carlrobert.codegpt.client.BaseModel;
import java.awt.Desktop;
import java.awt.event.ItemEvent;
import java.io.IOException;

View file

@ -1,7 +1,7 @@
package ee.carlrobert.chatgpt.ide.settings;
package ee.carlrobert.codegpt.ide.settings;
import com.intellij.openapi.options.Configurable;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import javax.swing.JComponent;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;

View file

@ -1,17 +1,17 @@
package ee.carlrobert.chatgpt.ide.settings;
package ee.carlrobert.codegpt.ide.settings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import ee.carlrobert.chatgpt.client.BaseModel;
import ee.carlrobert.codegpt.client.BaseModel;
import java.net.Proxy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@State(
name = "ee.carlrobert.chatgpt.ide.settings.SettingsState",
name = "ee.carlrobert.codegpt.ide.settings.SettingsState",
storages = @Storage("CodeGPTSettings.xml")
)
public class SettingsState implements PersistentStateComponent<SettingsState> {

View file

@ -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.chatgpt.ide.toolwindow.ChatGptToolWindow">
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="ee.carlrobert.codegpt.ide.toolwindow.ChatGptToolWindow">
<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>
@ -8,7 +8,7 @@
<properties/>
<border type="none"/>
<children>
<scrollpane id="8c1de" binding="scrollPane" custom-create="true">
<scrollpane id="8c1de" class="ee.carlrobert.codegpt.ide.toolwindow.components.ScrollPane" binding="scrollPane" custom-create="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
@ -32,7 +32,7 @@
</component>
</children>
</scrollpane>
<component id="2426b" class="javax.swing.JButton" binding="generateButton" custom-create="true">
<component id="2426b" class="ee.carlrobert.codegpt.ide.toolwindow.components.GenerateButton" binding="generateButton" custom-create="true">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
</constraints>

View file

@ -0,0 +1,223 @@
package ee.carlrobert.codegpt.ide.toolwindow;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createIconLabel;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createTextArea;
import static ee.carlrobert.codegpt.ide.toolwindow.components.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.openapi.wm.ToolWindow;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBScrollPane;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.settings.SettingsConfigurable;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.ide.toolwindow.components.GenerateButton;
import ee.carlrobert.codegpt.ide.toolwindow.components.LandingView;
import ee.carlrobert.codegpt.ide.toolwindow.components.ScrollPane;
import ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea;
import ee.carlrobert.codegpt.ide.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 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 org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.jetbrains.annotations.NotNull;
public class ChatGptToolWindow {
private static final List<SyntaxTextArea> textAreas = new ArrayList<>();
private final Project project;
private final ToolWindow toolWindow;
private JPanel chatGptToolWindowContent;
private ScrollPane scrollPane;
private ScrollablePanel scrollablePanel;
private JTextArea textArea;
private JScrollPane textAreaScrollPane;
private GenerateButton generateButton;
private boolean isLandingViewVisible;
public ChatGptToolWindow(@NotNull Project project, @NotNull ToolWindow toolWindow) {
this.project = project;
this.toolWindow = toolWindow;
}
public JPanel getContent() {
return chatGptToolWindowContent;
}
public void show() {
toolWindow.show();
}
public void displayUserMessage(String userMessage) {
if (isLandingViewVisible || ConversationsState.getCurrentConversation() == null) {
clearWindow();
}
addIconLabel(AllIcons.General.User, "User:");
scrollablePanel.add(createTextArea(userMessage));
scrollablePanel.validate();
scrollablePanel.repaint();
}
public void displayLandingView() {
isLandingViewVisible = true;
clearWindow();
var landingView = new LandingView();
scrollablePanel.add(landingView.createImageIconPanel());
addSpacing(16);
landingView.getQuestionPanels().forEach(panel -> {
scrollablePanel.add(panel);
addSpacing(16);
});
scrollablePanel.validate();
scrollablePanel.repaint();
}
public void displayConversation(Conversation conversation) {
clearWindow();
conversation.getMessages().forEach(message -> {
displayUserMessage(message.getPrompt());
addIconLabel(Icons.DefaultImageIcon, "ChatGPT:");
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
textArea.setText(message.getResponse());
textArea.displayCopyButton();
textArea.hideCaret();
scrollablePanel.add(textArea);
textAreas.add(textArea);
});
scrollToBottom();
scrollablePanel.validate();
scrollablePanel.repaint();
}
public void displayResponse(String prompt) {
addIconLabel(Icons.DefaultImageIcon, "ChatGPT:");
var settings = SettingsState.getInstance();
if (settings.isGPTOptionSelected && settings.apiKey.isEmpty()) {
notifyMissingCredential(project, "API key not provided.");
} else if (settings.isChatGPTOptionSelected && settings.accessToken.isEmpty()) {
notifyMissingCredential(project, "Access token not provided.");
} else {
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
addTextArea(textArea);
}
}
public void clearWindow() {
isLandingViewVisible = false;
generateButton.setVisible(false);
scrollablePanel.removeAll();
textAreas.clear();
}
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(SyntaxTextArea textArea, Runnable onRefresh) {
generateButton.setMode(GenerateButton.Mode.REFRESH, onRefresh);
textArea.displayCopyButton();
textArea.hideCaret();
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();
displayUserMessage(searchText);
displayResponse()
project.getService(ToolWindowService.class).sendMessage(searchText, project);
textArea.setText("");
scrollToBottom();
}
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)));
textAreaScrollPane.setViewportView(textArea);
textArea = new TextArea(this::handleSubmit, textAreaScrollPane);
scrollablePanel = new ScrollablePanel();
scrollablePanel.setLayout(new BoxLayout(scrollablePanel, BoxLayout.Y_AXIS));
scrollPane = new ScrollPane(scrollablePanel);
generateButton = new GenerateButton();
displayLandingView();
}
}

View file

@ -0,0 +1,4 @@
package ee.carlrobert.codegpt.ide.toolwindow;
public class ChatToolWindowContent {
}

View file

@ -0,0 +1,56 @@
package ee.carlrobert.codegpt.ide.toolwindow;
import static java.util.Objects.requireNonNull;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import java.util.Arrays;
import java.util.Optional;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
public class ContentManagerService {
private static ContentManagerService instance;
private final ContentManager contentManager;
private ContentManagerService(Project project) {
this.contentManager = requireNonNull(ToolWindowManager.getInstance(project).getToolWindow("CodeGPT")).getContentManager();
}
public static ContentManagerService getInstance(@NotNull Project project) {
if (instance == null) {
instance = new ContentManagerService(project);
}
return instance;
}
public void addContent(JPanel content, String displayName) {
contentManager.addContent(ApplicationManager.getApplication()
.getService(ContentFactory.class)
.createContent(content, displayName, false));
}
public void displayChatTab() {
tryFindChatTabContent().ifPresentOrElse(
contentManager::setSelectedContent,
() -> contentManager.setSelectedContent(requireNonNull(contentManager.getContent(0)))
);
}
public Optional<Content> tryFindChatTabContent() {
return Arrays.stream(contentManager.getContents())
.filter(content -> "Chat".equals(content.getTabName()))
.findFirst();
}
public boolean isChatTabSelected() {
return tryFindChatTabContent()
.filter(contentManager::isSelected)
.isPresent();
}
}

View file

@ -0,0 +1,44 @@
package ee.carlrobert.codegpt.ide.toolwindow;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
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.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.toolwindow.conversations.ConversationsToolWindow;
import org.jetbrains.annotations.NotNull;
public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
var toolWindowService = project.getService(ToolWindowService.class);
var chatToolWindow = new ChatGptToolWindow(project, toolWindow);
var conversationsToolWindow = new ConversationsToolWindow(project);
toolWindowService.setChatToolWindow(chatToolWindow);
var contentManagerService = ContentManagerService.getInstance(project);
contentManagerService.addContent(chatToolWindow.getContent(), "Chat");
contentManagerService.addContent(conversationsToolWindow.getContent(), "Conversation History");
toolWindow.addContentManagerListener(new ContentManagerListener() {
public void selectionChanged(@NotNull ContentManagerEvent event) {
var content = event.getContent();
if ("Conversation History".equals(content.getTabName()) && content.isSelected()) {
conversationsToolWindow.refresh();
}
}
});
displayRecentConversationIfPresent(toolWindowService, contentManagerService.isChatTabSelected());
}
private void displayRecentConversationIfPresent(ToolWindowService toolWindowService, boolean isChatTabSelected) {
var conversation = ConversationsState.getCurrentConversation();
if (conversation != null) {
if (isChatTabSelected) {
toolWindowService.getChatToolWindow().displayConversation(conversation);
}
}
}
}

View file

@ -0,0 +1,97 @@
package ee.carlrobert.codegpt.ide.toolwindow;
import com.intellij.ide.ui.LafManager;
import com.intellij.ide.ui.LafManagerListener;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.client.ClientFactory;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.conversations.message.Message;
import ee.carlrobert.codegpt.ide.settings.SettingsState;
import ee.carlrobert.codegpt.ide.toolwindow.components.SyntaxTextArea;
import icons.Icons;
import java.util.List;
import javax.swing.SwingWorker;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.jetbrains.annotations.NotNull;
public class ToolWindowService implements LafManagerListener {
private ChatGptToolWindow chatToolWindow;
@Override
public void lookAndFeelChanged(@NotNull LafManager source) {
chatToolWindow.changeStyle();
}
public void setChatToolWindow(ChatGptToolWindow chatToolWindow) {
this.chatToolWindow = chatToolWindow;
}
public ChatGptToolWindow getChatToolWindow() {
return chatToolWindow;
}
public void startRequest(String prompt, SyntaxTextArea textArea, Project project) {
var client = new ClientFactory().getClient();
chatToolWindow.displayGenerateButton(client::cancelRequest);
var conversationMessage = new Message(prompt);
new SwingWorker<Void, String>() {
protected Void doInBackground() {
client.getCompletionsAsync(
prompt,
this::publish,
(completedConversation) -> {
ConversationsState.getInstance().saveConversation(completedConversation);
stopGenerating(prompt, textArea, project);
},
(errorMessage) -> {
var currentConversation = ConversationsState.getCurrentConversation();
if (currentConversation != null) {
conversationMessage.setResponse(errorMessage);
currentConversation.addMessage(conversationMessage);
ConversationsState.getInstance().saveConversation(currentConversation);
}
textArea.append(errorMessage);
stopGenerating(prompt, textArea, project);
});
return null;
}
protected void process(List<String> chunks) {
for (String text : chunks) {
try {
textArea.append(text);
conversationMessage.setResponse(textArea.getText());
chatToolWindow.scrollToBottom();
} catch (Exception e) {
textArea.append("Something went wrong. Please try again later.");
throw new RuntimeException(e);
}
}
}
}.execute();
}
public void sendMessage(String prompt, Project project) {
chatToolWindow.addIconLabel(Icons.DefaultImageIcon, "ChatGPT:");
var settings = SettingsState.getInstance();
if (settings.isGPTOptionSelected && settings.apiKey.isEmpty()) {
chatToolWindow.notifyMissingCredential(project, "API key not provided.");
} else if (settings.isChatGPTOptionSelected && settings.accessToken.isEmpty()) {
chatToolWindow.notifyMissingCredential(project, "Access token not provided.");
} else {
var textArea = new SyntaxTextArea(true, true, SyntaxConstants.SYNTAX_STYLE_MARKDOWN);
chatToolWindow.addTextArea(textArea);
startRequest(prompt, textArea, project);
}
}
private void stopGenerating(String prompt, SyntaxTextArea textArea, Project project) {
chatToolWindow.stopGenerating(textArea, () -> {
sendMessage(prompt, project);
chatToolWindow.scrollToBottom();
});
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.toolwindow.components;
package ee.carlrobert.codegpt.ide.toolwindow.components;
import java.awt.*;
import javax.swing.*;

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.toolwindow.components;
package ee.carlrobert.codegpt.ide.toolwindow.components;
import com.intellij.icons.AllIcons;
import javax.swing.JButton;

View file

@ -0,0 +1,42 @@
package ee.carlrobert.codegpt.ide.toolwindow.components;
import static java.util.stream.Collectors.toList;
import icons.Icons;
import java.awt.GridBagLayout;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class LandingView {
private static final List<String> questions = List.of("How do I make an HTTP request in Javascript?",
"What is the difference between px, dip, dp, and sp?",
"How do I undo the most recent local commits in Git?",
"What is the difference between stack and heap?");
public List<JPanel> getQuestionPanels() {
return questions.stream()
.map(this::createQuestionPanel)
.collect(toList());
}
public JPanel createImageIconPanel() {
var imageIconPanel = new JPanel();
imageIconPanel.setLayout(new GridBagLayout());
var imageIconLabel = new JLabel(Icons.SunImageIcon);
imageIconLabel.setHorizontalAlignment(JLabel.CENTER);
imageIconPanel.add(imageIconLabel);
return imageIconPanel;
}
private JPanel createQuestionPanel(String question) {
var panel = new JPanel();
panel.setLayout(new GridBagLayout());
var label = new JLabel(question, SwingConstants.CENTER);
label.setHorizontalAlignment(JLabel.CENTER);
panel.add(label);
return panel;
}
}

View file

@ -0,0 +1,31 @@
package ee.carlrobert.codegpt.ide.toolwindow.components;
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.JBUI;
import java.awt.Adjustable;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JScrollBar;
import javax.swing.ScrollPaneConstants;
public class ScrollPane extends JBScrollPane {
public ScrollPane(ScrollablePanel scrollablePanel) {
super(scrollablePanel);
setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
setBorder(JBUI.Borders.empty(0, 8));
setViewportBorder(null);
}
public void scrollToBottom() {
JScrollBar verticalBar = getVerticalScrollBar();
verticalBar.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
Adjustable adjustable = e.getAdjustable();
adjustable.setValue(adjustable.getMaximum());
verticalBar.removeAdjustmentListener(this);
}
});
}
}

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.toolwindow;
package ee.carlrobert.codegpt.ide.toolwindow.components;
import com.intellij.ui.JBColor;
import java.awt.Component;
@ -14,7 +14,7 @@ import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
public class ToolWindowUtil {
public class SwingUtils {
public static JTextArea createTextArea(String selectedText) {
var textArea = new JTextArea();

View file

@ -1,6 +1,6 @@
package ee.carlrobert.chatgpt.ide.toolwindow.components;
package ee.carlrobert.codegpt.ide.toolwindow.components;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.createIconButton;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createIconButton;
import com.intellij.icons.AllIcons;
import com.intellij.util.ui.JBUI;

View file

@ -1,7 +1,7 @@
package ee.carlrobert.chatgpt.ide.toolwindow.components;
package ee.carlrobert.codegpt.ide.toolwindow.components;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.addShiftEnterInputMap;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.createIconButton;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.addShiftEnterInputMap;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.createIconButton;
import com.intellij.ui.JBColor;
import com.intellij.ui.components.JBTextArea;
@ -39,7 +39,6 @@ public class TextArea extends JBTextArea {
private FocusListener getFocusListener() {
return new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (getText().equals("Ask me anything...")) {
setText("");
@ -47,7 +46,6 @@ public class TextArea extends JBTextArea {
}
}
@Override
public void focusLost(FocusEvent e) {
if (getText().isEmpty()) {
setForeground(JBColor.GRAY);

View file

@ -1,11 +1,11 @@
package ee.carlrobert.chatgpt.ide.toolwindow.conversations;
package ee.carlrobert.codegpt.ide.toolwindow.conversations;
import static ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowUtil.justifyLeft;
import static ee.carlrobert.codegpt.ide.toolwindow.components.SwingUtils.justifyLeft;
import com.intellij.icons.AllIcons;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.GridBagConstraints;

View file

@ -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.chatgpt.ide.toolwindow.conversations.ConversationsToolWindow">
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="ee.carlrobert.codegpt.ide.toolwindow.conversations.ConversationsToolWindow">
<grid id="27dc6" binding="conversationsToolWindowContent" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>

View file

@ -1,15 +1,13 @@
package ee.carlrobert.chatgpt.ide.toolwindow.conversations;
package ee.carlrobert.codegpt.ide.toolwindow.conversations;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.componentsList.components.ScrollablePanel;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.components.JBScrollPane;
import ee.carlrobert.chatgpt.ide.conversations.Conversation;
import ee.carlrobert.chatgpt.ide.conversations.ConversationsState;
import ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService;
import java.util.Arrays;
import ee.carlrobert.codegpt.ide.conversations.Conversation;
import ee.carlrobert.codegpt.ide.conversations.ConversationsState;
import ee.carlrobert.codegpt.ide.toolwindow.ContentManagerService;
import ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService;
import java.util.Comparator;
import java.util.Objects;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
@ -19,14 +17,12 @@ import org.jetbrains.annotations.NotNull;
public class ConversationsToolWindow {
private final Project project;
private final ToolWindow toolWindow;
private JPanel conversationsToolWindowContent;
private JScrollPane scrollPane;
private ScrollablePanel scrollablePanel;
public ConversationsToolWindow(@NotNull Project project, @NotNull ToolWindow toolWindow) {
public ConversationsToolWindow(@NotNull Project project) {
this.project = project;
this.toolWindow = toolWindow;
refresh();
}
@ -47,17 +43,10 @@ public class ConversationsToolWindow {
private void addContent(Conversation conversation) {
var mainPanel = new RootConversationPanel(() -> {
ConversationsState.getInstance().setCurrentConversation(conversation);
var toolWindowService = project.getService(ToolWindowService.class);
var contentManager = toolWindow.getContentManager();
Arrays.stream(contentManager.getContents())
.filter(content -> "Chat".equals(content.getTabName()))
.findFirst()
.ifPresentOrElse(
contentManager::setSelectedContent,
() -> contentManager.setSelectedContent(Objects.requireNonNull(contentManager.getContent(0)))
);
toolWindowService.displayConversation(conversation);
ContentManagerService.getInstance(project).displayChatTab();
project.getService(ToolWindowService.class)
.getChatToolWindow()
.displayConversation(conversation);
});
var currentConversation = ConversationsState.getCurrentConversation();

View file

@ -1,4 +1,4 @@
package ee.carlrobert.chatgpt.ide.toolwindow.conversations;
package ee.carlrobert.codegpt.ide.toolwindow.conversations;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.JBUI;

View file

@ -1,5 +1,5 @@
<idea-plugin>
<id>ee.carlrobert.chatgpt</id>
<id>ee.carlrobert.codegpt</id>
<name>CodeGPT</name>
<vendor email="carlrobertoh@gmail.com" url="https://carlrobert.ee">Carl-Robert Linnupuu</vendor>
<description><![CDATA[
@ -102,34 +102,34 @@
<projectListeners>
<listener
class="ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService"
class="ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService"
topic="com.intellij.ide.ui.LafManagerListener"/>
</projectListeners>
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable id="settings.codegpt" parentId="tools" displayName="CodeGPT"
instance="ee.carlrobert.chatgpt.ide.settings.SettingsConfigurable"/>
<applicationService serviceImplementation="ee.carlrobert.chatgpt.ide.settings.SettingsState"/>
<applicationService serviceImplementation="ee.carlrobert.chatgpt.ide.conversations.ConversationsState"/>
<projectService serviceImplementation="ee.carlrobert.chatgpt.ide.toolwindow.ToolWindowService"/>
instance="ee.carlrobert.codegpt.ide.settings.SettingsConfigurable"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.ide.settings.SettingsState"/>
<applicationService serviceImplementation="ee.carlrobert.codegpt.ide.conversations.ConversationsState"/>
<projectService serviceImplementation="ee.carlrobert.codegpt.ide.toolwindow.ToolWindowService"/>
<toolWindow id="CodeGPT" icon="Icons.ToolWindowIcon" anchor="right"
factoryClass="ee.carlrobert.chatgpt.ide.toolwindow.ChatGptToolWindowFactory"/>
factoryClass="ee.carlrobert.codegpt.ide.toolwindow.ProjectToolWindowFactory"/>
</extensions>
<resource-bundle>messages.BasicActionsBundle</resource-bundle>
<actions>
<group id="CodeGPTEditorPopup">
<group id="ActionGroup" class="ee.carlrobert.chatgpt.ide.action.ActionGroup" popup="true" icon="Icons.DefaultIcon">
<action id="AskAction" class="ee.carlrobert.chatgpt.ide.action.AskAction" icon="AllIcons.Actions.Find"/>
<group id="ActionGroup" class="com.intellij.openapi.actionSystem.DefaultActionGroup" popup="true" icon="Icons.DefaultIcon">
<action id="AskAction" class="ee.carlrobert.codegpt.ide.action.AskAction" icon="AllIcons.Actions.Find"/>
<separator/>
<action id="CustomPromptAction" class="ee.carlrobert.chatgpt.ide.action.CustomPromptAction" icon="AllIcons.Actions.Run_anything"/>
<action id="CustomPromptAction" class="ee.carlrobert.codegpt.ide.action.CustomPromptAction" icon="AllIcons.Actions.Run_anything"/>
<separator/>
<action id="WriteTestsAction" class="ee.carlrobert.chatgpt.ide.action.WriteTestsAction"/>
<action id="FindBugsAction" class="ee.carlrobert.chatgpt.ide.action.FindBugsAction"/>
<action id="RefactorAction" class="ee.carlrobert.chatgpt.ide.action.RefactorAction"/>
<action id="OptimizeAction" class="ee.carlrobert.chatgpt.ide.action.OptimizeAction"/>
<action id="ExplainAction" class="ee.carlrobert.chatgpt.ide.action.ExplainAction"/>
<action id="WriteTestsAction" class="ee.carlrobert.codegpt.ide.action.WriteTestsAction"/>
<action id="FindBugsAction" class="ee.carlrobert.codegpt.ide.action.FindBugsAction"/>
<action id="RefactorAction" class="ee.carlrobert.codegpt.ide.action.RefactorAction"/>
<action id="OptimizeAction" class="ee.carlrobert.codegpt.ide.action.OptimizeAction"/>
<action id="ExplainAction" class="ee.carlrobert.codegpt.ide.action.ExplainAction"/>
</group>
<add-to-group group-id="EditorPopupMenu1" anchor="first"/>
<separator/>