+
+> **Note**: If you're already running a server and wish to configure the plugin against that, then simply select the port and click `Apply/OK`.
## Features
diff --git a/README.md b/README.md
index cd4ba38b..31960365 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,21 @@ Expected a different answer? Re-generate any response of your choosing.
- **Seamless conversations** - Chat with the AI regardless of the maximum token limitations
- **Predefined Actions** - Create your own editor actions or override the existing ones, saving time rewriting the same prompt repeatedly
+### Running locally
+
+**Linux or macOS**
+```shell
+git clone https://github.com/carlrobertoh/CodeGPT.git
+cd CodeGPT
+git submodule update
+./gradlew runIde
+```
+
+**Windows ARM64**
+```shell
+./gradlew runIde -Penv=win-arm64
+```
+
## Issues
See the [open issues][open-issues] for a full list of proposed features (and known issues).
diff --git a/build.gradle.kts b/build.gradle.kts
index 44e74a2b..051614ea 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,8 +1,24 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
+import java.io.FileInputStream
+import java.util.*
+
+val env = environment("env").getOrNull()
+
+fun loadProperties(filename: String): Properties = Properties().apply {
+ load(FileInputStream(filename))
+}
+
+fun properties(key: String): ProviderFile Size: %.2f GB
" + + "Max RAM Required: %.2f GB
" + + "", details.fileSize, details.maxRAMRequired); + } + + public void setSelectedModel(HuggingFaceModel model) { + huggingFaceComboBoxModel.setSelectedItem(model); + } + + public HuggingFaceModel getSelectedModel() { + return (HuggingFaceModel) huggingFaceComboBoxModel.getSelectedItem(); + } + + public void setCustomLlamaModelPath(String modelPath) { + customModelPathBrowserButton.setText(modelPath); + } + + public String getCustomLlamaModelPath() { + return customModelPathBrowserButton.getText(); + } + + public void setUseCustomLlamaModel(boolean useCustomLlamaModel) { + useCustomModelCheckBox.setSelected(useCustomLlamaModel); + } + + public boolean isUseCustomLlamaModel() { + return useCustomModelCheckBox.isSelected(); + } + + public void setPromptTemplate(PromptTemplate promptTemplate) { + promptTemplateComboBox.setSelectedItem(promptTemplate); + } + + public PromptTemplate getPromptTemplate() { + return promptTemplateComboBox.getItem(); + } + + private ComboBox" + llamaModel.getDescription() + "
") + .setBrowserLink(CodeGPTBundle.get("settingsConfigurable.service.llama.linkToModel.label"), model.getHuggingFaceURL()) + .installOn(helpIcon); + } + + static class ModelSize { + + private final int size; + + ModelSize(int size) { + this.size = size; + } + + int getSize() { + return size; + } + + @Override + public String toString() { + return size + "B"; + } + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/LlamaServiceSelectionForm.java b/src/main/java/ee/carlrobert/codegpt/settings/service/LlamaServiceSelectionForm.java new file mode 100644 index 00000000..dfac9d85 --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/LlamaServiceSelectionForm.java @@ -0,0 +1,163 @@ +package ee.carlrobert.codegpt.settings.service; + +import com.intellij.icons.AllIcons.Actions; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.panel.ComponentPanelBuilder; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.PortField; +import com.intellij.ui.TitledSeparator; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.fields.IntegerField; +import com.intellij.util.ui.FormBuilder; +import com.intellij.util.ui.JBUI; +import ee.carlrobert.codegpt.CodeGPTBundle; +import ee.carlrobert.codegpt.CodeGPTPlugin; +import ee.carlrobert.codegpt.completions.HuggingFaceModel; +import ee.carlrobert.codegpt.completions.llama.LlamaServerAgent; +import ee.carlrobert.codegpt.settings.state.LlamaSettingsState; +import ee.carlrobert.codegpt.util.OverlayUtils; +import java.awt.BorderLayout; +import java.io.File; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +public class LlamaServiceSelectionForm extends JPanel { + + private final LlamaModelPreferencesForm llamaModelPreferencesForm; + private final PortField portField; + private final IntegerField maxTokensField; + + public LlamaServiceSelectionForm() { + var llamaServerAgent = ApplicationManager.getApplication().getService(LlamaServerAgent.class); + var serverRunning = llamaServerAgent.isServerRunning(); + portField = new PortField(LlamaSettingsState.getInstance().getServerPort()); + portField.setEnabled(!serverRunning); + + var serverProgressPanel = new ServerProgressPanel(); + llamaModelPreferencesForm = new LlamaModelPreferencesForm(); + + maxTokensField = new IntegerField("max_tokens", 256, 4096); + maxTokensField.setColumns(12); + maxTokensField.setValue(2048); + maxTokensField.setEnabled(!serverRunning); + + var serverButton = new JButton(); + serverButton.setText(serverRunning ? + CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label") : + CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label")); + serverButton.setIcon(serverRunning ? Actions.Suspend : Actions.Execute); + serverButton.addActionListener(event -> { + if (llamaModelPreferencesForm.isUseCustomLlamaModel()) { + var customModelPath = llamaModelPreferencesForm.getCustomLlamaModelPath(); + if (customModelPath == null || customModelPath.isEmpty()) { + OverlayUtils.showBalloon( + CodeGPTBundle.get("validation.error.fieldRequired"), + MessageType.ERROR, + llamaModelPreferencesForm.getCustomModelPathBrowserButton()); + return; + } + } else { + if (!isModelExists(llamaModelPreferencesForm.getSelectedModel())) { + OverlayUtils.showBalloon( + CodeGPTBundle.get("settingsConfigurable.service.llama.overlay.modelNotDownloaded.text"), + MessageType.ERROR, + llamaModelPreferencesForm.getHuggingFaceModelComboBox()); + return; + } + } + + if (llamaServerAgent.isServerRunning()) { + setFormEnabled(true); + serverButton.setText(CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label")); + serverButton.setIcon(Actions.Execute); + serverProgressPanel.updateText(CodeGPTBundle.get("settingsConfigurable.service.llama.progress.stoppingServer")); + llamaServerAgent.stopAgent(); + } else { + setFormEnabled(false); + serverButton.setText(CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label")); + serverButton.setIcon(Actions.Suspend); + serverProgressPanel.startProgress(CodeGPTBundle.get("settingsConfigurable.service.llama.progress.startingServer")); + + // TODO: Move to LlamaModelPreferencesForm + var modelPath = llamaModelPreferencesForm.isUseCustomLlamaModel() ? + llamaModelPreferencesForm.getCustomLlamaModelPath() : + CodeGPTPlugin.getLlamaModelsPath() + + File.separator + + llamaModelPreferencesForm.getSelectedModel().getFileName(); + llamaServerAgent.startAgent( + modelPath, + maxTokensField.getValue(), + portField.getNumber(), + serverProgressPanel, + () -> { + setFormEnabled(false); + serverProgressPanel.displayComponent(new JBLabel( + "Server running", + Actions.Commit, + SwingConstants.LEADING)); + }); + } + }); + + var contextSizeHelpText = ComponentPanelBuilder.createCommentComponent( + CodeGPTBundle.get("settingsConfigurable.service.llama.contextSize.comment"), + true); + contextSizeHelpText.setBorder(JBUI.Borders.empty(0, 4)); + + setLayout(new BorderLayout()); + add(FormBuilder.createFormBuilder() + .addComponent(new TitledSeparator(CodeGPTBundle.get("settingsConfigurable.service.llama.modelPreferences.title"))) + .addComponent(withEmptyLeftBorder(llamaModelPreferencesForm.getForm())) + .addComponent(new TitledSeparator(CodeGPTBundle.get("settingsConfigurable.service.llama.serverPreferences.title"))) + .addComponent(withEmptyLeftBorder(FormBuilder.createFormBuilder() + .addLabeledComponent(CodeGPTBundle.get("settingsConfigurable.service.llama.contextSize.label"), maxTokensField) + .addComponentToRightColumn(contextSizeHelpText) + .addLabeledComponent(CodeGPTBundle.get("settingsConfigurable.service.llama.port.label"), JBUI.Panels.simplePanel() + .addToLeft(portField) + .addToRight(serverButton)) + .getPanel())) + .addVerticalGap(4) + .addComponent(withEmptyLeftBorder(serverProgressPanel)) + .addComponentFillVertically(new JPanel(), 0) + .getPanel()); + } + + private boolean isModelExists(HuggingFaceModel model) { + return FileUtil.exists( + CodeGPTPlugin.getLlamaModelsPath() + File.separator + model.getFileName()); + } + + private void setFormEnabled(boolean enabled) { + llamaModelPreferencesForm.enableFields(enabled); + portField.setEnabled(enabled); + maxTokensField.setEnabled(enabled); + } + + public void setServerPort(int serverPort) { + portField.setNumber(serverPort); + } + + public int getServerPort() { + return portField.getNumber(); + } + + public LlamaModelPreferencesForm getLlamaModelPreferencesForm() { + return llamaModelPreferencesForm; + } + + private JComponent withEmptyLeftBorder(JComponent component) { + component.setBorder(JBUI.Borders.emptyLeft(16)); + return component; + } + + public int getContextSize() { + return maxTokensField.getValue(); + } + + public void setContextSize(int contextSize) { + maxTokensField.setValue(contextSize); + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/ServerProgressPanel.java b/src/main/java/ee/carlrobert/codegpt/settings/service/ServerProgressPanel.java new file mode 100644 index 00000000..8e2ad0ad --- /dev/null +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/ServerProgressPanel.java @@ -0,0 +1,37 @@ +package ee.carlrobert.codegpt.settings.service; + +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.AsyncProcessIcon; +import java.awt.FlowLayout; +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class ServerProgressPanel extends JPanel { + + private final JBLabel label = new JBLabel(); + + public ServerProgressPanel() { + super(new FlowLayout(FlowLayout.LEADING, 0, 0)); + setVisible(false); + add(new AsyncProcessIcon("sign_in_spinner")); + add(Box.createHorizontalStrut(4)); + add(label); + } + + public void startProgress(String text) { + setVisible(true); + updateText(text); + } + + public void updateText(String text) { + label.setText(text); + } + + public void displayComponent(JComponent component) { + removeAll(); + add(component); + revalidate(); + repaint(); + } +} diff --git a/src/main/java/ee/carlrobert/codegpt/settings/ServiceSelectionForm.java b/src/main/java/ee/carlrobert/codegpt/settings/service/ServiceSelectionForm.java similarity index 65% rename from src/main/java/ee/carlrobert/codegpt/settings/ServiceSelectionForm.java rename to src/main/java/ee/carlrobert/codegpt/settings/service/ServiceSelectionForm.java index 057bc7cf..75c5029c 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/ServiceSelectionForm.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/ServiceSelectionForm.java @@ -1,58 +1,46 @@ -package ee.carlrobert.codegpt.settings; +package ee.carlrobert.codegpt.settings.service; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.ui.ComboBox; -import com.intellij.ui.JBColor; +import com.intellij.ui.EnumComboBoxModel; import com.intellij.ui.TitledSeparator; -import com.intellij.ui.components.*; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBPasswordField; +import com.intellij.ui.components.JBRadioButton; +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 com.intellij.util.ui.UIUtil; import ee.carlrobert.codegpt.CodeGPTBundle; +import ee.carlrobert.codegpt.completions.you.YouUserManager; +import ee.carlrobert.codegpt.completions.you.auth.AuthenticationNotifier; import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; import ee.carlrobert.codegpt.credentials.OpenAICredentialsManager; import ee.carlrobert.codegpt.settings.state.AzureSettingsState; import ee.carlrobert.codegpt.settings.state.OpenAISettingsState; -import ee.carlrobert.codegpt.settings.state.SettingsState; -import ee.carlrobert.codegpt.completions.you.YouUserManager; -import ee.carlrobert.codegpt.completions.you.auth.AuthenticationNotifier; import ee.carlrobert.codegpt.settings.state.YouSettingsState; -import ee.carlrobert.codegpt.telemetry.ui.utils.JBLabelUtils; import ee.carlrobert.codegpt.util.SwingUtils; import ee.carlrobert.llm.client.openai.completion.chat.OpenAIChatCompletionModel; -import ee.carlrobert.llm.completion.CompletionModel; - -import java.awt.*; import java.util.List; import java.util.Map; -import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JPanel; public class ServiceSelectionForm { + private static final Logger LOG = Logger.getInstance(ServiceSelectionForm.class); + private final Disposable parentDisposable; - private static final OpenAIChatCompletionModel[] DEFAULT_OPENAI_MODELS = new OpenAIChatCompletionModel[]{ - OpenAIChatCompletionModel.GPT_3_5, - OpenAIChatCompletionModel.GPT_3_5_16k, - OpenAIChatCompletionModel.GPT_4, - OpenAIChatCompletionModel.GPT_4_32k - }; - - private final JBRadioButton useOpenAIServiceRadioButton; - private final JBRadioButton useAzureServiceRadioButton; - private final JBPasswordField openAIApiKeyField; private final JBTextField openAIBaseHostField; private final JBTextField openAIPathField; private final JBTextField openAIOrganizationField; private final JPanel openAIServiceSectionPanel; - private final ComboBoxYour coupon code
" + + "Use CodeGPT coupon for free month of GPT-4.
\n" + + "\n" + + " Sign up here\n" + + "
\n" + + "\n" + + "