refactor: clean up old code

This commit is contained in:
Carl-Robert Linnupuu 2024-03-14 14:31:16 +02:00
parent 33c597d8e5
commit 42105bf308
67 changed files with 75 additions and 8227 deletions

View file

@ -3,7 +3,6 @@ package ee.carlrobert.codegpt;
import com.intellij.openapi.editor.EditorCustomElementRenderer;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.util.Key;
import ee.carlrobert.embedding.ReferencedFile;
import java.util.List;
public class CodeGPTKeys {

View file

@ -18,7 +18,6 @@ import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;

View file

@ -0,0 +1,72 @@
package ee.carlrobert.codegpt;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReferencedFile {
private final String fileName;
private final String filePath;
private final String fileContent;
public ReferencedFile(File file) {
this.fileName = file.getName();
this.filePath = file.getPath();
try {
this.fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public ReferencedFile(String fileName, String filePath, String fileContent) {
this.fileName = fileName;
this.filePath = filePath;
this.fileContent = fileContent;
}
public String getFileName() {
return fileName;
}
public String getFilePath() {
return filePath;
}
public String getFileContent() {
return fileContent;
}
public String getFileExtension() {
Pattern pattern = Pattern.compile("[^.]+$");
Matcher matcher = pattern.matcher(fileName);
if (matcher.find()) {
return matcher.group();
}
return "";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ReferencedFile that = (ReferencedFile) o;
return Objects.equals(filePath, that.filePath);
}
@Override
public int hashCode() {
return Objects.hash(filePath);
}
}

View file

@ -26,13 +26,13 @@ import com.intellij.util.ui.UI.PanelFactory;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.settings.IncludedFilesSettings;
import ee.carlrobert.codegpt.ui.UIUtil;
import ee.carlrobert.codegpt.ui.checkbox.FileCheckboxTree;
import ee.carlrobert.codegpt.ui.checkbox.PsiElementCheckboxTree;
import ee.carlrobert.codegpt.ui.checkbox.VirtualFileCheckboxTree;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.Dimension;
import java.io.IOException;
import java.nio.file.Files;

View file

@ -1,7 +1,7 @@
package ee.carlrobert.codegpt.actions;
import com.intellij.util.messages.Topic;
import ee.carlrobert.embedding.ReferencedFile;
import ee.carlrobert.codegpt.ReferencedFile;
import java.util.List;
public interface IncludeFilesInContextNotifier {

View file

@ -11,11 +11,11 @@ import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowContentManager;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

View file

@ -17,15 +17,11 @@ public class CompletionRequestHandler {
private static final Logger LOG = Logger.getInstance(CompletionRequestHandler.class);
private final StringBuilder messageBuilder = new StringBuilder();
private final boolean useContextualSearch;
private final CompletionResponseEventListener completionResponseEventListener;
private SwingWorker<Void, String> swingWorker;
private EventSource eventSource;
public CompletionRequestHandler(
boolean useContextualSearch,
CompletionResponseEventListener completionResponseEventListener) {
this.useContextualSearch = useContextualSearch;
public CompletionRequestHandler(CompletionResponseEventListener completionResponseEventListener) {
this.completionResponseEventListener = completionResponseEventListener;
}
@ -46,7 +42,7 @@ public class CompletionRequestHandler {
CompletionEventListener<String> eventListener) {
try {
return CompletionRequestService.getInstance()
.getChatCompletionAsync(callParameters, useContextualSearch, eventListener);
.getChatCompletionAsync(callParameters, eventListener);
} catch (Throwable ex) {
handleCallException(ex);
throw ex;

View file

@ -9,8 +9,8 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import ee.carlrobert.codegpt.CodeGPTPlugin;
import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.completions.llama.LlamaModel;
import ee.carlrobert.codegpt.completions.llama.PromptTemplate;
import ee.carlrobert.codegpt.conversations.Conversation;
@ -29,8 +29,6 @@ import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings;
import ee.carlrobert.codegpt.settings.service.you.YouSettings;
import ee.carlrobert.codegpt.telemetry.core.configuration.TelemetryConfiguration;
import ee.carlrobert.codegpt.telemetry.core.service.UserId;
import ee.carlrobert.embedding.EmbeddingsService;
import ee.carlrobert.embedding.ReferencedFile;
import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionRequest;
import ee.carlrobert.llm.client.anthropic.completion.ClaudeCompletionRequestMessage;
import ee.carlrobert.llm.client.llama.completion.LlamaCompletionRequest;
@ -66,18 +64,14 @@ public class CompletionRequestProvider {
"/prompts/fix-compile-errors.txt");
private final EncodingManager encodingManager = EncodingManager.getInstance();
private final EmbeddingsService embeddingsService;
private final Conversation conversation;
public CompletionRequestProvider(Conversation conversation) {
this.embeddingsService = new EmbeddingsService(
CompletionClientProvider.getOpenAIClient(),
CodeGPTPlugin.getPluginBasePath());
this.conversation = conversation;
}
public static String getPromptWithContext(List<ReferencedFile> referencedFiles,
String userPrompt) {
String userPrompt) {
var includedFilesSettings = IncludedFilesSettings.getCurrentState();
var repeatableContext = referencedFiles.stream()
.map(item -> includedFilesSettings.getRepeatableContext()
@ -184,11 +178,10 @@ public class CompletionRequestProvider {
public OpenAIChatCompletionRequest buildOpenAIChatCompletionRequest(
@Nullable String model,
CallParameters callParameters,
boolean useContextualSearch,
@Nullable String overriddenPath) {
var configuration = ConfigurationSettings.getCurrentState();
var builder = new OpenAIChatCompletionRequest.Builder(
buildMessages(model, callParameters, useContextualSearch))
buildMessages(model, callParameters))
.setModel(model)
.setMaxTokens(configuration.getMaxTokens())
.setStream(true)
@ -206,7 +199,7 @@ public class CompletionRequestProvider {
CallParameters callParameters) {
return buildCustomOpenAIChatCompletionRequest(
customConfiguration,
buildMessages(callParameters, false),
buildMessages(callParameters),
true);
}
@ -273,43 +266,33 @@ public class CompletionRequestProvider {
return request;
}
private List<OpenAIChatCompletionMessage> buildMessages(
CallParameters callParameters,
boolean useContextualSearch) {
private List<OpenAIChatCompletionMessage> buildMessages(CallParameters callParameters) {
var message = callParameters.getMessage();
var messages = new ArrayList<OpenAIChatCompletionMessage>();
if (useContextualSearch) {
var prompt = embeddingsService.buildPromptWithContext(
message.getPrompt());
LOG.info("Retrieved context:\n" + prompt);
messages.add(new OpenAIChatCompletionMessage("user", prompt));
} else {
if (callParameters.getConversationType() == ConversationType.DEFAULT) {
messages.add(new OpenAIChatCompletionMessage(
"system",
ConfigurationSettings.getCurrentState().getSystemPrompt()));
}
if (callParameters.getConversationType() == ConversationType.FIX_COMPILE_ERRORS) {
messages.add(new OpenAIChatCompletionMessage("system", FIX_COMPILE_ERRORS_SYSTEM_PROMPT));
}
for (var prevMessage : conversation.getMessages()) {
if (callParameters.isRetry() && prevMessage.getId().equals(message.getId())) {
break;
}
messages.add(new OpenAIChatCompletionMessage("user", prevMessage.getPrompt()));
messages.add(new OpenAIChatCompletionMessage("assistant", prevMessage.getResponse()));
}
messages.add(new OpenAIChatCompletionMessage("user", message.getPrompt()));
if (callParameters.getConversationType() == ConversationType.DEFAULT) {
messages.add(new OpenAIChatCompletionMessage(
"system",
ConfigurationSettings.getCurrentState().getSystemPrompt()));
}
if (callParameters.getConversationType() == ConversationType.FIX_COMPILE_ERRORS) {
messages.add(new OpenAIChatCompletionMessage("system", FIX_COMPILE_ERRORS_SYSTEM_PROMPT));
}
for (var prevMessage : conversation.getMessages()) {
if (callParameters.isRetry() && prevMessage.getId().equals(message.getId())) {
break;
}
messages.add(new OpenAIChatCompletionMessage("user", prevMessage.getPrompt()));
messages.add(new OpenAIChatCompletionMessage("assistant", prevMessage.getResponse()));
}
messages.add(new OpenAIChatCompletionMessage("user", message.getPrompt()));
return messages;
}
private List<OpenAIChatCompletionMessage> buildMessages(
@Nullable String model,
CallParameters callParameters,
boolean useContextualSearch) {
var messages = buildMessages(callParameters, useContextualSearch);
CallParameters callParameters) {
var messages = buildMessages(callParameters);
if (model == null
|| GeneralSettings.getCurrentState().getSelectedService() == ServiceType.YOU) {

View file

@ -61,68 +61,62 @@ public final class CompletionRequestService {
public EventSource getChatCompletionAsync(
CallParameters callParameters,
boolean useContextualSearch,
CompletionEventListener<String> eventListener) {
var requestProvider = new CompletionRequestProvider(callParameters.getConversation());
switch (GeneralSettings.getCurrentState().getSelectedService()) {
case OPENAI:
return switch (GeneralSettings.getCurrentState().getSelectedService()) {
case OPENAI -> {
var openAISettings = OpenAISettings.getCurrentState();
return CompletionClientProvider.getOpenAIClient().getChatCompletionAsync(
yield CompletionClientProvider.getOpenAIClient().getChatCompletionAsync(
requestProvider.buildOpenAIChatCompletionRequest(
openAISettings.getModel(),
callParameters,
useContextualSearch,
null),
eventListener);
case CUSTOM_OPENAI:
}
case CUSTOM_OPENAI -> {
var customConfiguration = CustomServiceSettings.getCurrentState();
return getCustomOpenAIChatCompletionAsync(
yield getCustomOpenAIChatCompletionAsync(
requestProvider.buildCustomOpenAIChatCompletionRequest(
customConfiguration,
callParameters),
eventListener);
case ANTHROPIC:
return CompletionClientProvider.getClaudeClient().getCompletionAsync(
requestProvider.buildAnthropicChatCompletionRequest(callParameters),
eventListener);
case AZURE:
}
case ANTHROPIC -> CompletionClientProvider.getClaudeClient().getCompletionAsync(
requestProvider.buildAnthropicChatCompletionRequest(callParameters),
eventListener);
case AZURE -> {
var azureSettings = AzureSettings.getCurrentState();
return CompletionClientProvider.getAzureClient().getChatCompletionAsync(
yield CompletionClientProvider.getAzureClient().getChatCompletionAsync(
requestProvider.buildOpenAIChatCompletionRequest(
null,
callParameters,
useContextualSearch,
azureSettings.isUsingCustomPath() ? azureSettings.getPath() : null),
eventListener);
case YOU:
return CompletionClientProvider.getYouClient().getChatCompletionAsync(
requestProvider.buildYouCompletionRequest(callParameters.getMessage()),
eventListener);
case LLAMA_CPP:
return CompletionClientProvider.getLlamaClient().getChatCompletionAsync(
requestProvider.buildLlamaCompletionRequest(
callParameters.getMessage(),
callParameters.getConversationType()),
eventListener);
default:
throw new IllegalArgumentException();
}
}
case YOU -> CompletionClientProvider.getYouClient().getChatCompletionAsync(
requestProvider.buildYouCompletionRequest(callParameters.getMessage()),
eventListener);
case LLAMA_CPP -> CompletionClientProvider.getLlamaClient().getChatCompletionAsync(
requestProvider.buildLlamaCompletionRequest(
callParameters.getMessage(),
callParameters.getConversationType()),
eventListener);
default -> throw new IllegalArgumentException();
};
}
public EventSource getCodeCompletionAsync(
InfillRequestDetails requestDetails,
CompletionEventListener<String> eventListener) {
var requestProvider = new CodeCompletionRequestProvider(requestDetails);
switch (GeneralSettings.getCurrentState().getSelectedService()) {
case OPENAI:
return CompletionClientProvider.getOpenAIClient()
.getCompletionAsync(requestProvider.buildOpenAIRequest(), eventListener);
case LLAMA_CPP:
return CompletionClientProvider.getLlamaClient()
.getChatCompletionAsync(requestProvider.buildLlamaRequest(), eventListener);
default:
throw new IllegalArgumentException("Code completion not supported for selected service");
}
return switch (GeneralSettings.getCurrentState().getSelectedService()) {
case OPENAI -> CompletionClientProvider.getOpenAIClient()
.getCompletionAsync(requestProvider.buildOpenAIRequest(), eventListener);
case LLAMA_CPP -> CompletionClientProvider.getLlamaClient()
.getChatCompletionAsync(requestProvider.buildLlamaRequest(), eventListener);
default ->
throw new IllegalArgumentException("Code completion not supported for selected service");
};
}
public void generateCommitMessageAsync(

View file

@ -1,28 +0,0 @@
package ee.carlrobert.codegpt.indexes;
import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import org.jetbrains.annotations.NotNull;
public class CodebaseIndexingAction extends AnAction {
public CodebaseIndexingAction() {
super("Update Indexes", "Update indexes", AllIcons.Actions.Refresh);
}
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
var project = event.getProject();
if (project != null) {
var folderStructureTreePanel = new FolderStructureTreePanel(project);
var show = OverlayUtil.showFileStructureDialog(project, folderStructureTreePanel);
if (show == OK_EXIT_CODE) {
new CodebaseIndexingTask(project, folderStructureTreePanel.getReferencedFiles()).run();
}
}
}
}

View file

@ -1,11 +0,0 @@
package ee.carlrobert.codegpt.indexes;
import com.intellij.util.messages.Topic;
public interface CodebaseIndexingCompletedNotifier {
Topic<CodebaseIndexingCompletedNotifier> INDEXING_COMPLETED_TOPIC =
Topic.create("codebaseIndexingCompleted", CodebaseIndexingCompletedNotifier.class);
void indexingCompleted();
}

View file

@ -1,81 +0,0 @@
package ee.carlrobert.codegpt.indexes;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.jelmerk.knn.Item;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.CodeGPTPlugin;
import ee.carlrobert.codegpt.completions.CompletionClientProvider;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.EmbeddingsService;
import ee.carlrobert.embedding.ReferencedFile;
import ee.carlrobert.vector.VectorStore;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
public class CodebaseIndexingTask extends Task.Backgroundable {
private static final Logger LOG = Logger.getInstance(CodebaseIndexingTask.class);
private final Project project;
private final List<ReferencedFile> referencedFiles;
private final EmbeddingsService embeddingsService;
public CodebaseIndexingTask(Project project, List<ReferencedFile> referencedFiles) {
super(project, CodeGPTBundle.get("codebaseIndexing.task.title"), true);
this.project = project;
this.referencedFiles = referencedFiles;
this.embeddingsService = new EmbeddingsService(
CompletionClientProvider.getOpenAIClient(),
CodeGPTPlugin.getPluginBasePath());
}
public void run() {
ProgressManager.getInstance()
.runProcessWithProgressAsynchronously(this, new BackgroundableProcessIndicator(this));
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
LOG.info("Indexing started");
String fileContent;
try {
fileContent = new ObjectMapper().writeValueAsString(Map.of("content", referencedFiles));
} catch (JsonProcessingException e) {
throw new RuntimeException("Unable to serialize json file");
}
if (!com.intellij.openapi.util.io.FileUtil.exists(CodeGPTPlugin.getIndexStorePath())) {
FileUtil.tryCreateDirectory(CodeGPTPlugin.getIndexStorePath());
}
FileUtil.createFile(
CodeGPTPlugin.getProjectIndexStorePath(project), "index.json", fileContent);
try {
indicator.setFraction(0);
List<Item<Object, double[]>> embeddings =
embeddingsService.createEmbeddings(referencedFiles, indicator);
VectorStore.getInstance(CodeGPTPlugin.getPluginBasePath()).save(embeddings);
OverlayUtil.showNotification("Indexing completed", NotificationType.INFORMATION);
project.getMessageBus()
.syncPublisher(CodebaseIndexingCompletedNotifier.INDEXING_COMPLETED_TOPIC)
.indexingCompleted();
} catch (RuntimeException e) {
LOG.error("Something went wrong while indexing the codebase", e);
} finally {
if (indicator.isRunning()) {
indicator.stop();
}
}
}
}

View file

@ -1,242 +0,0 @@
package ee.carlrobert.codegpt.indexes;
import static java.util.stream.Collectors.toList;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.VcsIgnoreManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl;
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
import com.intellij.ui.CheckboxTree;
import com.intellij.ui.CheckboxTreeListener;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.AsyncProcessIcon;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import org.jetbrains.annotations.NotNull;
public class FolderStructureTreePanel {
private CheckboxTree checkboxTree;
private final AsyncProcessIcon loadingFilesSpinner;
private final JPanel rootPanelContainer;
private final VcsIgnoreManager ignoreManager;
private final ChangeListManager changeListManager;
private long totalSize = 0;
public FolderStructureTreePanel(@NotNull Project project) {
this.ignoreManager = VcsIgnoreManager.getInstance(project);
this.loadingFilesSpinner = new AsyncProcessIcon("loading_files");
this.changeListManager = ChangeListManager.getInstance(project);
var projectDirectory = ProjectUtil.guessProjectDir(project);
if (projectDirectory == null) {
throw new RuntimeException("Couldn't find project directory");
}
var rootNode = new CheckedTreeNode(projectDirectory);
rootPanelContainer = new JPanel(new BorderLayout());
CompletableFuture
.runAsync(() -> traverseDirectory(rootNode, projectDirectory))
.thenRun(() -> SwingUtilities.invokeLater(() -> {
checkboxTree = createCheckboxTree(rootNode, true);
loadingFilesSpinner.setVisible(false);
updatePanel();
}));
checkboxTree = createCheckboxTree(rootNode, false);
rootPanelContainer.add(createRootPanel());
rootPanelContainer.add(createFooterPanel(), BorderLayout.SOUTH);
}
private CheckboxTree createCheckboxTree(CheckedTreeNode rootNode, boolean enabled) {
checkboxTree = new CheckboxTree(createFileTypesRenderer(), rootNode);
checkboxTree.setEditable(enabled);
checkboxTree.setEnabled(enabled);
checkboxTree.addCheckboxTreeListener(new CheckboxTreeListener() {
@Override
public void nodeStateChanged(@NotNull CheckedTreeNode node) {
try {
var length = ((VirtualFileImpl) node.getUserObject()).getLength();
if (node.isChecked()) {
totalSize += length;
} else {
totalSize -= length;
}
} catch (Throwable ignored) {
// ignore
}
}
});
checkboxTree.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
updatePanel();
}
});
return checkboxTree;
}
private void updatePanel() {
rootPanelContainer.removeAll();
rootPanelContainer.add(createRootPanel());
rootPanelContainer.add(createFooterPanel(), BorderLayout.SOUTH);
rootPanelContainer.revalidate();
rootPanelContainer.repaint();
}
public JPanel getPanel() {
return rootPanelContainer;
}
private JPanel createRootPanel() {
var scrollPane = ScrollPaneFactory.createScrollPane(checkboxTree);
scrollPane.setPreferredSize(JBUI.size(250, 375));
return JBUI.Panels.simplePanel().addToCenter(scrollPane);
}
private JPanel createFooterPanel() {
var panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 8));
if (loadingFilesSpinner.isVisible()) {
panel.add(new JBLabel("Total size:"));
panel.add(loadingFilesSpinner);
} else {
panel.add(new JBLabel("Total size: "
+ FileUtil.convertFileSize(totalSize) + " ~ "
+ (FileUtil.convertLongValue(totalSize / 4)) + " tokens " + " ~ "
+ new DecimalFormat("#.##")
.format(((double) (totalSize / 4) / 1000) * 0.0001) + " $"));
}
return panel;
}
public List<ReferencedFile> getReferencedFiles() {
return getCheckedVirtualFiles().stream()
.map(item -> new ReferencedFile(new File(item.getPath())))
.collect(toList());
}
private List<VirtualFileImpl> getCheckedVirtualFiles() {
return Arrays.stream(checkboxTree.getCheckedNodes(
VirtualFileSystemEntry.class,
node -> node instanceof VirtualFileImpl))
.map(entry -> (VirtualFileImpl) entry)
.collect(toList());
}
private void processChildFile(@NotNull CheckedTreeNode node, @NotNull VirtualFile file) {
long fileSize = file.getLength();
try {
if (node.isChecked()) {
node.setChecked(!changeListManager.isIgnoredFile(file)
&& !ignoreManager.isPotentiallyIgnoredFile(file)
&& FileUtil.isUtf8File(file.getPath())
&& fileSize < Math.pow(1024, 2));
}
if (node.isChecked()) {
totalSize += fileSize;
}
} catch (RuntimeException ignored) {
// ignore
}
}
private void traverseDirectory(@NotNull CheckedTreeNode parentNode,
@NotNull VirtualFile projectDirectory) {
for (VirtualFile childFile : projectDirectory.getChildren()) {
var node = new CheckedTreeNode(childFile);
parentNode.add(node);
var potentiallyIgnored = ignoredFileDirectories.parallelStream()
.anyMatch(it -> it.equalsIgnoreCase(childFile.getName()));
if (!parentNode.isChecked() || potentiallyIgnored) {
node.setChecked(false);
}
if (childFile.isDirectory()) {
traverseDirectory(node, childFile);
} else {
processChildFile(node, childFile);
}
}
}
private @NotNull CheckboxTree.CheckboxTreeCellRenderer createFileTypesRenderer() {
return new CheckboxTree.CheckboxTreeCellRenderer() {
@Override
public void customizeRenderer(JTree t,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean focus) {
if (!(value instanceof CheckedTreeNode)) {
return;
}
var node = (CheckedTreeNode) value;
var userObject = node.getUserObject();
if (userObject instanceof VirtualFileSystemEntry) {
getTextRenderer().append(((VirtualFileSystemEntry) userObject).getName());
if (userObject instanceof VirtualDirectoryImpl) {
getTextRenderer().setIcon(AllIcons.Nodes.Folder);
} else {
var fileType = FileTypeManager.getInstance()
.getFileTypeByFile((VirtualFileSystemEntry) userObject);
getTextRenderer().setIcon(fileType.getIcon());
getTextRenderer().append(
" - " + FileUtil.convertFileSize(
((VirtualFileSystemEntry) userObject).getLength()));
}
}
}
};
}
private static final List<String> ignoredFileDirectories = List.of(
"node_modules",
".git",
".svn",
".bzr",
".cvs",
".m2",
".idea",
".vscode",
".project",
".settings",
"node_modules",
"vendor",
"lib",
"build",
"target",
"media",
"logs",
"uploads");
}

View file

@ -6,7 +6,6 @@ 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.toolwindow.chat.contextual.ContextualChatToolWindowPanel;
import ee.carlrobert.codegpt.toolwindow.chat.standard.StandardChatToolWindowPanel;
import ee.carlrobert.codegpt.toolwindow.conversations.ConversationsToolWindow;
import javax.swing.JComponent;
@ -16,12 +15,9 @@ public class ProjectToolWindowFactory implements ToolWindowFactory, DumbAware {
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
var chatToolWindowPanel = new StandardChatToolWindowPanel(project, toolWindow.getDisposable());
// var contextualChatToolWindowPanel =
// new ContextualChatToolWindowPanel(project, toolWindow.getDisposable());
var conversationsToolWindow = new ConversationsToolWindow(project);
addContent(toolWindow, chatToolWindowPanel, "Chat");
// addContent(toolWindow, contextualChatToolWindowPanel, "Contextual Chat");
addContent(toolWindow, conversationsToolWindow.getContent(), "Chat History");
toolWindow.addContentManagerListener(new ContentManagerListener() {
public void selectionChanged(@NotNull ContentManagerEvent event) {

View file

@ -14,6 +14,7 @@ import com.intellij.ui.JBColor;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.ActionType;
import ee.carlrobert.codegpt.completions.CallParameters;
import ee.carlrobert.codegpt.completions.CompletionRequestHandler;
@ -37,7 +38,6 @@ import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextArea;
import ee.carlrobert.codegpt.toolwindow.chat.ui.textarea.UserPromptTextAreaHeader;
import ee.carlrobert.codegpt.util.EditorUtil;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@ -51,7 +51,6 @@ public abstract class ChatToolWindowTabPanel implements Disposable {
private static final Logger LOG = Logger.getInstance(ChatToolWindowTabPanel.class);
private final boolean useContextualSearch;
private final JPanel rootPanel;
private final Conversation conversation;
private final UserPromptTextArea userPromptTextArea;
@ -69,7 +68,6 @@ public abstract class ChatToolWindowTabPanel implements Disposable {
boolean useContextualSearch) {
this.project = project;
this.conversation = conversation;
this.useContextualSearch = useContextualSearch;
conversationService = ConversationService.getInstance();
toolWindowScrollablePanel = new ChatToolWindowScrollablePanel();
totalTokensPanel = new TotalTokensPanel(
@ -217,7 +215,6 @@ public abstract class ChatToolWindowTabPanel implements Disposable {
}
var requestHandler = new CompletionRequestHandler(
useContextualSearch,
new ToolWindowCompletionResponseEventListener(
conversationService,
responsePanel,

View file

@ -1,113 +0,0 @@
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
import static javax.swing.event.HyperlinkEvent.EventType.ACTIVATED;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.CodeGPTPlugin;
import ee.carlrobert.codegpt.indexes.CodebaseIndexingCompletedNotifier;
import ee.carlrobert.codegpt.indexes.CodebaseIndexingTask;
import ee.carlrobert.codegpt.indexes.FolderStructureTreePanel;
import ee.carlrobert.codegpt.settings.GeneralSettingsConfigurable;
import ee.carlrobert.codegpt.toolwindow.chat.ui.ResponsePanel;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import ee.carlrobert.codegpt.ui.UIUtil;
import ee.carlrobert.vector.VectorStore;
import javax.swing.JTextPane;
import javax.swing.event.HyperlinkEvent;
class ContextualChatToolWindowLandingPanel extends ResponsePanel {
private static final Logger LOG = Logger.getInstance(ContextualChatToolWindowLandingPanel.class);
private final Project project;
private final EditorActionEvent actionEvent;
ContextualChatToolWindowLandingPanel(Project project, EditorActionEvent actionEvent) {
this.project = project;
this.actionEvent = actionEvent;
addContent(createContent());
project.getMessageBus()
.connect()
.subscribe(CodebaseIndexingCompletedNotifier.INDEXING_COMPLETED_TOPIC,
(CodebaseIndexingCompletedNotifier) () -> updateContent(createContent()));
}
private JTextPane createContent() {
var description = UIUtil.createTextPane("", false, this::handleHyperlinkClicked);
if (VectorStore.getInstance(CodeGPTPlugin.getPluginBasePath()).isIndexExists()) {
description.setText("<html>"
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
+ "Feel free to ask me anything about your codebase, and I'll be your helpful guide, "
+ "dedicated to providing you with the best answers possible!"
+ "</p>"
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
+ "Here are a few examples of how I might be helpful:"
+ "</p>"
+ "<ul>"
+ "<li>"
+ "<a href=\"LIST_DEPENDENCIES\">List all the dependencies that the project uses</a>"
+ "</li>"
+ "<li>"
+ "<a href=\"SCHEDULED_TASKS\">Are there any scheduled tasks or background jobs "
+ "running in our codebase, and if so, what are they responsible for?</a>"
+ "</li>"
+ "<li>"
+ "<a href=\"AUTHENTICATION_MECHANISM\">Can you provide an overview of the "
+ "authentication and authorization mechanism implemented in our application?</a>"
+ "</li>"
+ "</ul>"
+ "</html>");
} else {
description.setText("<html>"
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
+ "It looks like you haven't indexed your codebase yet."
+ "</p>"
+ "<p style=\"margin-top: 4px; margin-bottom: 4px;\">"
+ "<a href=\"START_INDEXING\">Start indexing</a> your codebase to get "
+ "access to contextual chat experience."
+ "</p>"
+ "</html>");
}
return description;
}
private void handleHyperlinkClicked(HyperlinkEvent event) {
if (ACTIVATED.equals(event.getEventType())) {
if (event.getURL() == null) {
switch (event.getDescription()) {
case "LOGIN":
ShowSettingsUtil.getInstance()
.showSettingsDialog(project, GeneralSettingsConfigurable.class);
break;
case "LIST_DEPENDENCIES":
actionEvent.handleAction("List all the dependencies that the project uses");
break;
case "SCHEDULED_TASKS":
actionEvent.handleAction("Are there any scheduled tasks or background "
+ "jobs running in our codebase, and if so, what are they responsible for?");
break;
case "AUTHENTICATION_MECHANISM":
actionEvent.handleAction("Can you provide an overview of the authentication "
+ "and authorization mechanism implemented in our application?");
break;
case "START_INDEXING":
var folderStructureTreePanel = new FolderStructureTreePanel(project);
var show = OverlayUtil.showFileStructureDialog(project, folderStructureTreePanel);
if (show == OK_EXIT_CODE) {
new CodebaseIndexingTask(project, folderStructureTreePanel.getReferencedFiles())
.run();
}
break;
default:
LOG.error("Could not trigger action {}", event.getDescription());
}
} else {
UIUtil.handleHyperlinkClicked(event);
}
}
}
}

View file

@ -1,40 +0,0 @@
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.Disposer;
import ee.carlrobert.codegpt.actions.toolwindow.ClearChatWindowAction;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.indexes.CodebaseIndexingAction;
import org.jetbrains.annotations.NotNull;
public class ContextualChatToolWindowPanel extends SimpleToolWindowPanel {
public ContextualChatToolWindowPanel(
@NotNull Project project,
@NotNull Conversation conversation,
@NotNull Disposable parentDisposable) {
super(true);
var tabPanel = new ContextualChatToolWindowTabPanel(project, conversation);
setToolbar(createActionToolbar(tabPanel).getComponent());
setContent(tabPanel.getContent());
Disposer.register(parentDisposable, tabPanel);
}
private ActionToolbar createActionToolbar(ContextualChatToolWindowTabPanel tabPanel) {
var actionGroup = new DefaultActionGroup("TOOLBAR_ACTION_GROUP", false);
actionGroup.add(new ClearChatWindowAction(tabPanel::displayLandingView));
actionGroup.addSeparator();
actionGroup.add(new CodebaseIndexingAction());
var toolbar = ActionManager.getInstance()
.createActionToolbar("NAVIGATION_BAR_TOOLBAR", actionGroup, false);
toolbar.setTargetComponent(this);
return toolbar;
}
}

View file

@ -1,26 +0,0 @@
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
import com.intellij.openapi.project.Project;
import ee.carlrobert.codegpt.completions.ConversationType;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.codegpt.conversations.message.Message;
import ee.carlrobert.codegpt.toolwindow.chat.ChatToolWindowTabPanel;
import javax.swing.JComponent;
import org.jetbrains.annotations.NotNull;
public class ContextualChatToolWindowTabPanel extends ChatToolWindowTabPanel {
public ContextualChatToolWindowTabPanel(
@NotNull Project project,
@NotNull Conversation conversation) {
super(project, conversation, true);
displayLandingView();
}
@Override
protected JComponent getLandingView() {
return new ContextualChatToolWindowLandingPanel(
project,
(prompt) -> sendMessage(new Message(prompt), ConversationType.DEFAULT));
}
}

View file

@ -1,7 +0,0 @@
package ee.carlrobert.codegpt.toolwindow.chat.contextual;
@FunctionalInterface
public interface EditorActionEvent {
void handleAction(String prompt);
}

View file

@ -8,6 +8,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
import ee.carlrobert.codegpt.actions.toolwindow.ClearChatWindowAction;
import ee.carlrobert.codegpt.actions.toolwindow.CreateNewConversationAction;
@ -15,7 +16,6 @@ import ee.carlrobert.codegpt.actions.toolwindow.OpenInEditorAction;
import ee.carlrobert.codegpt.conversations.ConversationService;
import ee.carlrobert.codegpt.conversations.ConversationsState;
import ee.carlrobert.codegpt.toolwindow.chat.ui.SelectedFilesNotification;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.BorderLayout;
import java.util.List;
import javax.swing.JPanel;

View file

@ -11,8 +11,8 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.JBUI.CurrentTheme.NotificationInfo;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.BorderLayout;
import java.nio.file.Paths;
import java.util.List;

View file

@ -14,9 +14,9 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.CodeGPTKeys;
import ee.carlrobert.codegpt.EncodingManager;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.actions.IncludeFilesInContextNotifier;
import ee.carlrobert.codegpt.conversations.Conversation;
import ee.carlrobert.embedding.ReferencedFile;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

View file

@ -12,7 +12,6 @@ import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DoNotAskOption;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.MessageType;
@ -21,12 +20,8 @@ import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.Balloon.Position;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.JBFont;
import com.intellij.util.ui.JBUI;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.conversations.ConversationsState;
import ee.carlrobert.codegpt.indexes.FolderStructureTreePanel;
import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings;
import ee.carlrobert.codegpt.util.EditorUtil;
import java.awt.Point;
@ -44,30 +39,6 @@ public class OverlayUtil {
Notifications.Bus.notify(getDefaultNotification(content, type));
}
public static int showFileStructureDialog(
Project project,
FolderStructureTreePanel folderStructureTreePanel) {
var dialogBuilder = new DialogBuilder(project);
dialogBuilder.setNorthPanel(JBUI.Panels.simplePanel(new JBLabel(
"<html>"
+ "<p>Indexing files enables direct queries related to your codebase.</p>"
+ "<br/>"
+ "<p>File indexing occurs locally on your computer; "
+ "no files are sent to any 3rd party services.</p>"
+ "<p>For additional information, refer to the "
+ "<a href=\"https://google.com\">CodeGPT documentation</a>.</p>"
+ "</html>")
.setCopyable(true)
.setAllowAutoWrapping(true)
.withFont(JBFont.medium()))
.withBorder(JBUI.Borders.emptyBottom(12)));
dialogBuilder.setCenterPanel(folderStructureTreePanel.getPanel());
dialogBuilder.addOkAction().setText("Start Indexing");
dialogBuilder.addCancelAction();
dialogBuilder.setTitle("Choose Files for Indexing");
return dialogBuilder.show();
}
public static int showDeleteConversationDialog() {
return Messages.showYesNoDialog(
CodeGPTBundle.get("dialog.deleteConversation.description"),

View file

@ -5,8 +5,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CheckboxTree;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.ui.ColoredTreeCellRenderer;
import ee.carlrobert.codegpt.ReferencedFile;
import ee.carlrobert.codegpt.util.file.FileUtil;
import ee.carlrobert.embedding.ReferencedFile;
import java.util.List;
import org.jetbrains.annotations.NotNull;

View file

@ -9,7 +9,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.file.PsiDirectoryImpl;
import com.intellij.ui.CheckedTreeNode;
import ee.carlrobert.embedding.ReferencedFile;
import ee.carlrobert.codegpt.ReferencedFile;
import java.io.File;
import java.util.Arrays;
import java.util.List;

View file

@ -6,7 +6,7 @@ import com.intellij.icons.AllIcons;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.util.PlatformIcons;
import ee.carlrobert.embedding.ReferencedFile;
import ee.carlrobert.codegpt.ReferencedFile;
import java.io.File;
import java.util.Arrays;
import java.util.List;
@ -53,8 +53,7 @@ public class VirtualFileCheckboxTree extends FileCheckboxTree {
return new FileCheckboxTreeCellRenderer() {
@Override
void updatePresentation(Object userObject) {
if (userObject instanceof VirtualFile) {
VirtualFile virtualFile = (VirtualFile) userObject;
if (userObject instanceof VirtualFile virtualFile) {
if (virtualFile.isDirectory()) {
getTextRenderer().append(virtualFile.getName());
getTextRenderer().setIcon(PlatformIcons.FOLDER_ICON);