feat: add server and build logs for llama.cpp
Some checks failed
Build / Build (push) Has been cancelled
Build / Verify Plugin (push) Has been cancelled

This commit is contained in:
Carl-Robert Linnupuu 2025-07-12 18:38:37 +01:00
parent 556089f25e
commit 6cfbd98566
30 changed files with 2231 additions and 1086 deletions

View file

@ -48,16 +48,9 @@ public class CompletionClientProvider {
public static LlamaClient getLlamaClient() {
var llamaSettings = LlamaSettings.getCurrentState();
var builder = new LlamaClient.Builder()
.setPort(llamaSettings.getServerPort());
if (!llamaSettings.isRunLocalServer()) {
builder.setHost(llamaSettings.getBaseHost());
String apiKey = getCredential(CredentialKey.LlamaApiKey.INSTANCE);
if (apiKey != null && !apiKey.isBlank()) {
builder.setApiKey(apiKey);
}
}
return builder.build(getDefaultClientBuilder());
return new LlamaClient.Builder()
.setPort(llamaSettings.getServerPort())
.build(getDefaultClientBuilder());
}
public static OllamaClient getOllamaClient() {

View file

@ -1,254 +0,0 @@
package ee.carlrobert.codegpt.completions.llama;
import static java.lang.String.format;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessListener;
import com.intellij.execution.process.ProcessOutputType;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Key;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.CodeGPTPlugin;
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
import ee.carlrobert.codegpt.settings.service.llama.form.ServerProgressPanel;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Service
public final class LlamaServerAgent implements Disposable {
private static final Logger LOG = Logger.getInstance(LlamaServerAgent.class);
private @Nullable OSProcessHandler makeSetupProcessHandler;
private @Nullable OSProcessHandler makeBuildProcessHandler;
private @Nullable OSProcessHandler startServerProcessHandler;
private ServerProgressPanel activeServerProgressPanel;
private boolean stoppedByUser;
public void startAgent(
LlamaServerStartupParams params,
ServerProgressPanel serverProgressPanel,
Runnable onSuccess,
Consumer<ServerProgressPanel> onServerStopped) {
this.activeServerProgressPanel = serverProgressPanel;
ApplicationManager.getApplication().invokeLater(() -> {
try {
stoppedByUser = false;
serverProgressPanel.displayText(
CodeGPTBundle.get("llamaServerAgent.buildingProject.description"));
makeSetupProcessHandler = new OSProcessHandler(getCMakeSetupCommandLine(params));
makeSetupProcessHandler.addProcessListener(new ProcessAdapter() {
private final List<String> errorLines = new CopyOnWriteArrayList<>();
@Override
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
if (ProcessOutputType.isStderr(outputType)) {
errorLines.add(event.getText());
return;
}
LOG.info(event.getText());
}
@Override
public void processTerminated(@NotNull ProcessEvent event) {
int exitCode = event.getExitCode();
LOG.info(format("CMake setup exited with code %d", exitCode));
if (stoppedByUser) {
onServerStopped.accept(activeServerProgressPanel);
return;
}
if (exitCode != 0) {
showServerError(String.join(",", errorLines), onServerStopped);
return;
}
try {
makeBuildProcessHandler = new OSProcessHandler(getCMakeBuildCommandLine(params));
makeBuildProcessHandler.addProcessListener(
getMakeProcessListener(params, onSuccess, onServerStopped));
makeBuildProcessHandler.startNotify();
} catch (ExecutionException e) {
showServerError(e.getMessage(), onServerStopped);
}
}
});
makeSetupProcessHandler.startNotify();
} catch (ExecutionException e) {
showServerError(e.getMessage(), onServerStopped);
}
});
}
public void stopAgent() {
stoppedByUser = true;
if (makeSetupProcessHandler != null) {
makeSetupProcessHandler.destroyProcess();
}
if (startServerProcessHandler != null) {
startServerProcessHandler.destroyProcess();
}
}
public boolean isServerRunning() {
return (makeSetupProcessHandler != null
&& makeSetupProcessHandler.isStartNotified()
&& !makeSetupProcessHandler.isProcessTerminated())
|| (startServerProcessHandler != null
&& startServerProcessHandler.isStartNotified()
&& !startServerProcessHandler.isProcessTerminated());
}
private ProcessListener getMakeProcessListener(
LlamaServerStartupParams params,
Runnable onSuccess,
Consumer<ServerProgressPanel> onServerStopped) {
LOG.info("Building llama project");
return new ProcessAdapter() {
private final List<String> errorLines = new CopyOnWriteArrayList<>();
@Override
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
if (ProcessOutputType.isStderr(outputType)) {
errorLines.add(event.getText());
return;
}
LOG.info(event.getText());
}
@Override
public void processTerminated(@NotNull ProcessEvent event) {
int exitCode = event.getExitCode();
LOG.info(format("Server build exited with code %d", exitCode));
if (stoppedByUser) {
onServerStopped.accept(activeServerProgressPanel);
return;
}
if (exitCode != 0) {
showServerError(String.join(",", errorLines), onServerStopped);
return;
}
try {
LOG.info("Booting up llama server");
activeServerProgressPanel.displayText(
CodeGPTBundle.get("llamaServerAgent.serverBootup.description"));
startServerProcessHandler = new OSProcessHandler.Silent(getServerCommandLine(params));
startServerProcessHandler.addProcessListener(
getProcessListener(params.port(), onSuccess, onServerStopped));
startServerProcessHandler.startNotify();
} catch (ExecutionException ex) {
showServerError(ex.getMessage(), onServerStopped);
}
}
};
}
private ProcessListener getProcessListener(
int port,
Runnable onSuccess,
Consumer<ServerProgressPanel> onServerStopped) {
return new ProcessAdapter() {
private final ObjectMapper objectMapper = new ObjectMapper();
private final List<String> errorLines = new CopyOnWriteArrayList<>();
@Override
public void processTerminated(@NotNull ProcessEvent event) {
LOG.info(format("Server stopped with code %d", event.getExitCode()));
if (stoppedByUser) {
onServerStopped.accept(activeServerProgressPanel);
} else {
showServerError(String.join(",", errorLines), onServerStopped);
}
}
@Override
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
LOG.info(event.getText());
// TODO: Use proper successful boot up validation
if (event.getText().contains("server is listening")) {
LOG.info("Server up and running!");
LlamaSettings.getCurrentState().setServerPort(port);
onSuccess.run();
}
}
};
}
private void showServerError(String errorText, Consumer<ServerProgressPanel> onServerStopped) {
onServerStopped.accept(activeServerProgressPanel);
LOG.info("Unable to start llama server:\n" + errorText);
OverlayUtil.showClosableBalloon(errorText, MessageType.ERROR, activeServerProgressPanel);
}
private static GeneralCommandLine getCMakeSetupCommandLine(LlamaServerStartupParams params) {
GeneralCommandLine cmakeSetupCommand = new GeneralCommandLine().withCharset(
StandardCharsets.UTF_8);
cmakeSetupCommand.setExePath("cmake");
cmakeSetupCommand.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
cmakeSetupCommand.addParameters("-B", "build");
cmakeSetupCommand.withEnvironment(params.additionalEnvironmentVariables());
cmakeSetupCommand.setRedirectErrorStream(false);
return cmakeSetupCommand;
}
private static GeneralCommandLine getCMakeBuildCommandLine(LlamaServerStartupParams params) {
GeneralCommandLine cmakeBuildCommand = new GeneralCommandLine().withCharset(
StandardCharsets.UTF_8);
cmakeBuildCommand.setExePath("cmake");
cmakeBuildCommand.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
cmakeBuildCommand.addParameters("--build", "build", "--config", "Release", "-j", "4");
cmakeBuildCommand.withEnvironment(params.additionalEnvironmentVariables());
cmakeBuildCommand.setRedirectErrorStream(false);
return cmakeBuildCommand;
}
private GeneralCommandLine getServerCommandLine(LlamaServerStartupParams params) {
GeneralCommandLine commandLine = new GeneralCommandLine().withCharset(StandardCharsets.UTF_8);
commandLine.setExePath("./build/bin/llama-server");
commandLine.withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath());
commandLine.addParameters(
"-m", params.modelPath(),
"-c", String.valueOf(params.contextLength()),
"--port", String.valueOf(params.port()),
"-t", String.valueOf(params.threads()));
commandLine.addParameters(params.additionalRunParameters());
commandLine.withEnvironment(params.additionalEnvironmentVariables());
commandLine.setRedirectErrorStream(false);
return commandLine;
}
public void setActiveServerProgressPanel(
ServerProgressPanel activeServerProgressPanel) {
this.activeServerProgressPanel = activeServerProgressPanel;
}
@Override
public void dispose() {
if (makeSetupProcessHandler != null && !makeSetupProcessHandler.isProcessTerminated()) {
makeSetupProcessHandler.destroyProcess();
}
if (startServerProcessHandler != null && !startServerProcessHandler.isProcessTerminated()) {
startServerProcessHandler.destroyProcess();
}
}
}

View file

@ -1,6 +1,5 @@
package ee.carlrobert.codegpt.settings.service.llama;
import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LlamaApiKey;
import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP;
import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
import static org.apache.commons.lang3.SystemUtils.IS_OS_MAC_OSX;
@ -13,7 +12,6 @@ import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
import ee.carlrobert.codegpt.completions.HuggingFaceModel;
import ee.carlrobert.codegpt.completions.llama.LlamaModel;
import ee.carlrobert.codegpt.completions.llama.PromptTemplate;
import ee.carlrobert.codegpt.credentials.CredentialsStore;
import ee.carlrobert.codegpt.settings.GeneralSettings;
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm;
import java.io.File;
@ -23,7 +21,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
@State(name = "CodeGPT", storages = @Storage("CodeGPT_LlamaSettings.xml"))
@ -40,17 +37,12 @@ public class LlamaSettings implements PersistentStateComponent<LlamaSettingsStat
@Override
public void loadState(@NotNull LlamaSettingsState state) {
this.state = state;
// Catch if model's name has changed which could lead to
// HuggingFaceModel or PromptTemplates not being found
if (this.state.getHuggingFaceModel() == null) {
this.state.setHuggingFaceModel(HuggingFaceModel.CODE_QWEN_2_5_1_5B_Q8_0);
}
if (this.state.getLocalModelPromptTemplate() == null) {
this.state.setLocalModelPromptTemplate(PromptTemplate.CODE_QWEN);
}
if (this.state.getRemoteModelInfillPromptTemplate() == null) {
this.state.setRemoteModelInfillPromptTemplate(InfillPromptTemplate.CODE_QWEN_2_5);
}
if (this.state.getLocalModelInfillPromptTemplate() == null) {
this.state.setLocalModelInfillPromptTemplate(InfillPromptTemplate.CODE_QWEN);
}
@ -60,13 +52,10 @@ public class LlamaSettings implements PersistentStateComponent<LlamaSettingsStat
return getInstance().getState();
}
/**
* Code Completions enabled in settings and a model with InfillPromptTemplate selected.
*/
public static boolean isCodeCompletionsPossible() {
return getInstance().getState().isCodeCompletionsEnabled()
&& LlamaModel.findByHuggingFaceModel(getInstance().getState().getHuggingFaceModel())
.getInfillPromptTemplate() != null;
&& LlamaModel.findByHuggingFaceModel(getInstance().getState().getHuggingFaceModel())
.getInfillPromptTemplate() != null;
}
public static LlamaSettings getInstance() {
@ -74,15 +63,12 @@ public class LlamaSettings implements PersistentStateComponent<LlamaSettingsStat
}
public boolean isModified(LlamaSettingsForm form) {
return !form.getCurrentState().equals(state)
|| !StringUtils.equals(
form.getLlamaServerPreferencesForm().getApiKey(),
CredentialsStore.getCredential(LlamaApiKey.INSTANCE));
return !form.getCurrentState().equals(state);
}
public static boolean isRunnable() {
return (IS_OS_MAC_OSX || IS_OS_LINUX)
&& GeneralSettings.getCurrentState().getSelectedService() == LLAMA_CPP;
&& GeneralSettings.getCurrentState().getSelectedService() == LLAMA_CPP;
}
public static boolean isRunnable(HuggingFaceModel model) {
@ -97,19 +83,18 @@ public class LlamaSettings implements PersistentStateComponent<LlamaSettingsStat
return Paths.get(System.getProperty("user.home"), ".codegpt/models/gguf");
}
// Copied from LlamaModelPreferencesForm
public String getActualModelPath() {
return state.isUseCustomModel()
? state.getCustomLlamaModelPath()
: getLlamaModelsPath() + File.separator
? state.getCustomLlamaModelPath()
: getLlamaModelsPath() + File.separator
+ state.getHuggingFaceModel().getFileName();
}
public static List<String> getAdditionalParametersList(String additionalParameters) {
return Arrays.stream(additionalParameters.split(","))
.map(String::trim)
.filter(s -> !s.isBlank())
.toList();
.map(String::trim)
.filter(s -> !s.isBlank())
.toList();
}
public static Map<String, String> getAdditionalEnvironmentVariablesMap(

View file

@ -1,6 +1,5 @@
package ee.carlrobert.codegpt.settings.service.llama;
import com.intellij.openapi.util.SystemInfoRt;
import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
import ee.carlrobert.codegpt.completions.HuggingFaceModel;
import ee.carlrobert.codegpt.completions.llama.PromptTemplate;
@ -10,15 +9,11 @@ import java.util.Objects;
public class LlamaSettingsState {
private boolean runLocalServer = SystemInfoRt.isUnix;
private boolean useCustomModel;
private String customLlamaModelPath = "";
private HuggingFaceModel huggingFaceModel = HuggingFaceModel.CODE_QWEN_2_5_1_5B_Q8_0;
private PromptTemplate localModelPromptTemplate = PromptTemplate.LLAMA;
private PromptTemplate remoteModelPromptTemplate = PromptTemplate.LLAMA;
private InfillPromptTemplate localModelInfillPromptTemplate = InfillPromptTemplate.CODE_LLAMA;
private InfillPromptTemplate remoteModelInfillPromptTemplate = InfillPromptTemplate.CODE_LLAMA;
private String baseHost = "http://localhost:8080";
private Integer serverPort = getRandomAvailablePortOrDefault();
private int contextSize = 2048;
private int threads = 8;
@ -73,39 +68,6 @@ public class LlamaSettingsState {
this.localModelInfillPromptTemplate = localModelInfillPromptTemplate;
}
public InfillPromptTemplate getRemoteModelInfillPromptTemplate() {
return remoteModelInfillPromptTemplate;
}
public void setRemoteModelInfillPromptTemplate(
InfillPromptTemplate remoteModelInfillPromptTemplate) {
this.remoteModelInfillPromptTemplate = remoteModelInfillPromptTemplate;
}
public boolean isRunLocalServer() {
return runLocalServer;
}
public void setRunLocalServer(boolean runLocalServer) {
this.runLocalServer = runLocalServer;
}
public String getBaseHost() {
return baseHost;
}
public void setBaseHost(String baseHost) {
this.baseHost = baseHost;
}
public PromptTemplate getRemoteModelPromptTemplate() {
return remoteModelPromptTemplate;
}
public void setRemoteModelPromptTemplate(
PromptTemplate remoteModelPromptTemplate) {
this.remoteModelPromptTemplate = remoteModelPromptTemplate;
}
public Integer getServerPort() {
return serverPort;
@ -212,8 +174,7 @@ public class LlamaSettingsState {
return false;
}
LlamaSettingsState that = (LlamaSettingsState) o;
return runLocalServer == that.runLocalServer
&& useCustomModel == that.useCustomModel
return useCustomModel == that.useCustomModel
&& contextSize == that.contextSize
&& threads == that.threads
&& topK == that.topK
@ -223,10 +184,7 @@ public class LlamaSettingsState {
&& Objects.equals(customLlamaModelPath, that.customLlamaModelPath)
&& huggingFaceModel == that.huggingFaceModel
&& localModelPromptTemplate == that.localModelPromptTemplate
&& remoteModelPromptTemplate == that.remoteModelPromptTemplate
&& localModelInfillPromptTemplate == that.localModelInfillPromptTemplate
&& remoteModelInfillPromptTemplate == that.remoteModelInfillPromptTemplate
&& Objects.equals(baseHost, that.baseHost)
&& Objects.equals(serverPort, that.serverPort)
&& Objects.equals(additionalParameters, that.additionalParameters)
&& Objects.equals(additionalBuildParameters, that.additionalBuildParameters)
@ -236,9 +194,9 @@ public class LlamaSettingsState {
@Override
public int hashCode() {
return Objects.hash(runLocalServer, useCustomModel, customLlamaModelPath, huggingFaceModel,
localModelPromptTemplate, remoteModelPromptTemplate, localModelInfillPromptTemplate,
remoteModelInfillPromptTemplate, baseHost, serverPort, contextSize, threads,
return Objects.hash(useCustomModel, customLlamaModelPath, huggingFaceModel,
localModelPromptTemplate, localModelInfillPromptTemplate,
serverPort, contextSize, threads,
additionalParameters, additionalBuildParameters, additionalEnvironmentVariables, topK, topP,
minP, repeatPenalty,
codeCompletionsEnabled);

View file

@ -5,7 +5,6 @@ import static ee.carlrobert.codegpt.settings.service.llama.LlamaSettings.isModel
import static java.lang.String.format;
import static java.util.Collections.emptyMap;
import com.intellij.icons.AllIcons.Actions;
import com.intellij.icons.AllIcons.General;
import com.intellij.ide.HelpTooltip;
import com.intellij.openapi.actionSystem.AnAction;
@ -14,6 +13,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.ui.panel.ComponentPanelBuilder;
@ -34,24 +34,34 @@ import ee.carlrobert.codegpt.settings.service.llama.LlamaSettingsState;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class LlamaModelPreferencesForm {
private static final String PREDEFINED_MODEL_FORM_CARD_CODE = "PredefinedModelSettings";
private static final String CUSTOM_MODEL_FORM_CARD_CODE = "CustomModelSettings";
private static final String GROUP_DOWNLOADED = "Downloaded";
private static final String GROUP_NOT_DOWNLOADED = "Not Downloaded";
private static final Map<Integer, Map<Integer, ModelDetails>> modelDetailsMap = Map.of(
7, Map.of(
3, new ModelDetails(3.30, 5.80),
@ -69,11 +79,11 @@ public class LlamaModelPreferencesForm {
private final TextFieldWithBrowseButton browsableCustomModelTextField;
private final ComboBox<LlamaModel> modelComboBox;
private final ComboBox<ModelSize> modelSizeComboBox;
private final ComboBox<HuggingFaceModel> huggingFaceModelComboBox;
private final JBLabel modelExistsIcon;
private final DefaultComboBoxModel<HuggingFaceModel> huggingFaceComboBoxModel;
private final ComboBox<Object> huggingFaceModelComboBox;
private final DefaultComboBoxModel<Object> huggingFaceComboBoxModel;
private final JBLabel helpIcon;
private final JPanel downloadModelActionLinkWrapper;
private final JPanel modelActionsWrapper;
private final JBLabel progressLabel;
private final JBLabel modelDetailsLabel;
private final CardLayout cardLayout;
@ -84,59 +94,55 @@ public class LlamaModelPreferencesForm {
public LlamaModelPreferencesForm() {
cardLayout = new CardLayout();
progressLabel = new JBLabel("");
progressLabel.setBorder(JBUI.Borders.emptyLeft(2));
progressLabel.setFont(JBUI.Fonts.smallFont());
modelExistsIcon = new JBLabel(Actions.Checked);
var llamaSettings = LlamaSettings.getCurrentState();
modelExistsIcon.setVisible(isModelExists(llamaSettings.getHuggingFaceModel()));
progressLabel = createProgressLabel();
helpIcon = new JBLabel(General.ContextHelp);
huggingFaceComboBoxModel = new DefaultComboBoxModel<>();
var llamaSettings = LlamaSettings.getCurrentState();
var llm = llamaSettings.getHuggingFaceModel();
var llamaModel = LlamaModel.findByHuggingFaceModel(llm);
var selectableModels = llamaModel.getHuggingFaceModels().stream()
.filter(model -> model.getParameterSize() == llm.getParameterSize())
.toList();
huggingFaceComboBoxModel.addAll(selectableModels);
huggingFaceComboBoxModel.setSelectedItem(llm);
downloadModelActionLinkWrapper = new JPanel(new BorderLayout());
downloadModelActionLinkWrapper.setBorder(JBUI.Borders.emptyLeft(2));
downloadModelActionLinkWrapper.add(
createDownloadModelLink(
progressLabel,
downloadModelActionLinkWrapper,
huggingFaceComboBoxModel),
BorderLayout.WEST);
initializeHuggingFaceModel(llamaModel, llm);
downloadModelActionLinkWrapper = createActionPanel();
modelActionsWrapper = createActionPanel();
updateModelActionsPanel(llm);
modelDetailsLabel = new JBLabel();
huggingFaceModelComboBox = createModelQuantizationComboBox(huggingFaceComboBoxModel);
huggingFaceModelComboBox = createModelQuantizationComboBox();
var llamaServerAgent = ApplicationManager.getApplication().getService(LlamaServerAgent.class);
huggingFaceModelComboBox.setEnabled(!llamaServerAgent.isServerRunning());
var serverRunning = llamaServerAgent.isServerRunning();
huggingFaceModelComboBox.setEnabled(!serverRunning);
var modelSizeComboBoxModel = new DefaultComboBoxModel<ModelSize>();
var modelComboBoxModel = new DefaultComboBoxModel<LlamaModel>();
modelComboBoxModel.addAll(LlamaModel.getSorted());
var modelComboBoxModel = createLlamaModelComboBoxModel();
modelComboBox = createModelComboBox(
modelComboBoxModel, llamaModel, llm, llamaServerAgent, modelSizeComboBoxModel);
modelComboBox.setEnabled(!llamaServerAgent.isServerRunning());
modelComboBox.setEnabled(!serverRunning);
modelSizeComboBox = createModelSizeComboBox(
modelComboBoxModel,
modelSizeComboBoxModel,
llamaServerAgent,
huggingFaceComboBoxModel);
browsableCustomModelTextField = createBrowsableCustomModelTextField(
!llamaServerAgent.isServerRunning());
llamaServerAgent);
browsableCustomModelTextField = createBrowsableCustomModelTextField(!serverRunning);
browsableCustomModelTextField.setText(llamaSettings.getCustomLlamaModelPath());
localPromptTemplatePanel = new ChatPromptTemplatePanel(
llamaSettings.getLocalModelPromptTemplate(),
!llamaServerAgent.isServerRunning());
!serverRunning);
predefinedModelRadioButton = new JBRadioButton("Use pre-defined model",
!llamaSettings.isUseCustomModel());
customModelRadioButton = new JBRadioButton("Use custom model",
llamaSettings.isUseCustomModel());
infillPromptTemplatePanel = new InfillPromptTemplatePanel(
llamaSettings.getLocalModelInfillPromptTemplate(),
!llamaServerAgent.isServerRunning()
);
!serverRunning);
}
public JPanel getForm() {
@ -164,12 +170,15 @@ public class LlamaModelPreferencesForm {
return browsableCustomModelTextField;
}
@SuppressWarnings("unchecked")
public ComboBox<HuggingFaceModel> getHuggingFaceModelComboBox() {
return huggingFaceModelComboBox;
return (ComboBox<HuggingFaceModel>) (ComboBox<?>) huggingFaceModelComboBox;
}
@Nullable
public HuggingFaceModel getSelectedModel() {
return (HuggingFaceModel) huggingFaceComboBoxModel.getSelectedItem();
var selected = huggingFaceComboBoxModel.getSelectedItem();
return selected instanceof HuggingFaceModel ? (HuggingFaceModel) selected : null;
}
public String getCustomLlamaModelPath() {
@ -189,9 +198,40 @@ public class LlamaModelPreferencesForm {
}
public String getActualModelPath() {
return isUseCustomLlamaModel()
? getCustomLlamaModelPath()
: getLlamaModelsPath().resolve(getSelectedModel().getFileName()).toString();
if (isUseCustomLlamaModel()) {
return getCustomLlamaModelPath();
}
var selectedModel = getSelectedModel();
return selectedModel != null
? getLlamaModelsPath().resolve(selectedModel.getFileName()).toString()
: "";
}
private JBLabel createProgressLabel() {
var label = new JBLabel("");
label.setBorder(JBUI.Borders.emptyLeft(4));
label.setFont(JBUI.Fonts.smallFont());
return label;
}
private JPanel createActionPanel() {
var panel = new JPanel(new BorderLayout());
panel.setBorder(JBUI.Borders.emptyLeft(4));
return panel;
}
private void initializeHuggingFaceModel(LlamaModel llamaModel, HuggingFaceModel llm) {
var selectableModels = llamaModel.getHuggingFaceModels().stream()
.filter(model -> model.getParameterSize() == llm.getParameterSize())
.toList();
populateModelComboBoxWithGroups(selectableModels);
huggingFaceComboBoxModel.setSelectedItem(llm);
}
private DefaultComboBoxModel<LlamaModel> createLlamaModelComboBoxModel() {
var model = new DefaultComboBoxModel<LlamaModel>();
model.addAll(LlamaModel.getSorted());
return model;
}
private JPanel createFormPanelCards() {
@ -199,6 +239,7 @@ public class LlamaModelPreferencesForm {
formPanelCards.setBorder(JBUI.Borders.emptyLeft(16));
formPanelCards.add(createPredefinedModelForm(), PREDEFINED_MODEL_FORM_CARD_CODE);
formPanelCards.add(createCustomModelForm(), CUSTOM_MODEL_FORM_CARD_CODE);
cardLayout.show(
formPanelCards,
predefinedModelRadioButton.isSelected()
@ -218,15 +259,27 @@ public class LlamaModelPreferencesForm {
buttonGroup.add(predefinedModelRadioButton);
buttonGroup.add(customModelRadioButton);
var predefinedModelHelpText = createHelpText(
"settingsConfigurable.service.llama.predefinedModel.comment");
var customModelHelpText = createHelpText(
"settingsConfigurable.service.llama.customModel.comment");
var radioPanel = new JPanel();
radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.PAGE_AXIS));
radioPanel.add(predefinedModelRadioButton);
radioPanel.add(Box.createVerticalStrut(4));
radioPanel.add(predefinedModelHelpText);
radioPanel.add(customModelRadioButton);
radioPanel.add(Box.createVerticalStrut(8));
radioPanel.add(customModelHelpText);
return radioPanel;
}
private Component createHelpText(String bundleKey) {
var helpText = ComponentPanelBuilder.createCommentComponent(
CodeGPTBundle.get(bundleKey), true);
helpText.setBorder(JBUI.Borders.empty(0, 28, 8, 0));
return helpText;
}
private JPanel createCustomModelForm() {
var customModelHelpText = ComponentPanelBuilder.createCommentComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.customModelPath.comment"),
@ -254,17 +307,8 @@ public class LlamaModelPreferencesForm {
true);
quantizationHelpText.setBorder(JBUI.Borders.empty(0, 4));
var modelComboBoxWrapper = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
modelComboBoxWrapper.add(modelComboBox);
modelComboBoxWrapper.add(Box.createHorizontalStrut(8));
modelComboBoxWrapper.add(helpIcon);
modelComboBoxWrapper.add(Box.createHorizontalStrut(4));
modelComboBoxWrapper.add(modelExistsIcon);
var huggingFaceModelComboBoxWrapper = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
huggingFaceModelComboBoxWrapper.add(huggingFaceModelComboBox);
huggingFaceModelComboBoxWrapper.add(Box.createHorizontalStrut(8));
huggingFaceModelComboBoxWrapper.add(modelDetailsLabel);
var modelComboBoxWrapper = createModelComboBoxWrapper();
var huggingFaceModelComboBoxWrapper = createHuggingFaceModelComboBoxWrapper();
return FormBuilder.createFormBuilder()
.addLabeledComponent(CodeGPTBundle.get("settingsConfigurable.shared.model.label"),
@ -278,11 +322,28 @@ public class LlamaModelPreferencesForm {
.addComponentToRightColumn(quantizationHelpText)
.addComponentToRightColumn(downloadModelActionLinkWrapper)
.addComponentToRightColumn(progressLabel)
.addComponentToRightColumn(modelActionsWrapper)
.addVerticalGap(4)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
private JPanel createModelComboBoxWrapper() {
var wrapper = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
wrapper.add(modelComboBox);
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(helpIcon);
return wrapper;
}
private JPanel createHuggingFaceModelComboBoxWrapper() {
var wrapper = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
wrapper.add(huggingFaceModelComboBox);
wrapper.add(Box.createHorizontalStrut(8));
wrapper.add(modelDetailsLabel);
return wrapper;
}
private String getHuggingFaceModelDetailsHtml(HuggingFaceModel model) {
int parameterSize = model.getParameterSize();
int quantization = model.getQuantization();
@ -312,20 +373,26 @@ public class LlamaModelPreferencesForm {
comboBox.setPreferredSize(new Dimension(280, comboBox.getPreferredSize().height));
comboBox.setSelectedItem(llamaModel);
initializeModelSizes(llamaModel, llm, modelSizeComboBoxModel);
comboBox.addItemListener(e -> {
var selectedModel = (LlamaModel) e.getItem();
var hfm = selectedModel.getLastExistingModelOrFirst();
var modelSize = initializeModelSizes(selectedModel, hfm, modelSizeComboBoxModel);
var huggingFaceModels = selectedModel.filterSelectedModelsBySize(modelSize);
huggingFaceComboBoxModel.removeAllElements();
huggingFaceComboBoxModel.addAll(huggingFaceModels);
huggingFaceComboBoxModel.setSelectedItem(hfm);
modelSizeComboBox.setEnabled(
modelSizeComboBox.getModel().getSize() > 1 && !llamaServerAgent.isServerRunning());
});
comboBox.addItemListener(
e -> handleModelSelection(e, modelSizeComboBoxModel, llamaServerAgent));
return comboBox;
}
private void handleModelSelection(
ItemEvent e,
DefaultComboBoxModel<ModelSize> modelSizeComboBoxModel,
LlamaServerAgent llamaServerAgent) {
var selectedModel = (LlamaModel) e.getItem();
var hfm = selectedModel.getLastExistingModelOrFirst();
var modelSize = initializeModelSizes(selectedModel, hfm, modelSizeComboBoxModel);
var huggingFaceModels = selectedModel.filterSelectedModelsBySize(modelSize);
populateModelComboBoxWithGroups(huggingFaceModels);
huggingFaceComboBoxModel.setSelectedItem(hfm);
modelSizeComboBox.setEnabled(
modelSizeComboBox.getModel().getSize() > 1 && !llamaServerAgent.isServerRunning());
}
private static ModelSize initializeModelSizes(
LlamaModel llamaModel,
HuggingFaceModel hfm,
@ -333,60 +400,98 @@ public class LlamaModelPreferencesForm {
var modelSizes = llamaModel.getSortedUniqueModelSizes();
modelSizeComboBoxModel.removeAllElements();
modelSizeComboBoxModel.addAll(modelSizes);
var selectedModelSize = modelSizes.stream()
.filter(ms -> ms.size() == hfm.getParameterSize())
.findFirst().orElse(modelSizes.get(0));
var selectedModelSize = findMatchingModelSize(modelSizes, hfm.getParameterSize())
.orElse(modelSizes.get(0));
modelSizeComboBoxModel.setSelectedItem(selectedModelSize);
return selectedModelSize;
}
private static Optional<ModelSize> findMatchingModelSize(List<ModelSize> modelSizes,
int parameterSize) {
return modelSizes.stream()
.filter(ms -> ms.size() == parameterSize)
.findFirst();
}
private ComboBox<ModelSize> createModelSizeComboBox(
ComboBoxModel<LlamaModel> llamaModelComboBoxModel,
DefaultComboBoxModel<ModelSize> modelSizeComboBoxModel,
LlamaServerAgent llamaServerAgent,
DefaultComboBoxModel<HuggingFaceModel> huggingFaceComboBoxModel) {
LlamaServerAgent llamaServerAgent) {
var comboBox = new ComboBox<>(modelSizeComboBoxModel);
comboBox.setPreferredSize(modelComboBox.getPreferredSize());
comboBox.setSelectedItem(modelSizeComboBoxModel.getSelectedItem());
comboBox.setEnabled(
modelSizeComboBoxModel.getSize() > 1 && !llamaServerAgent.isServerRunning());
comboBox.addItemListener(e -> {
var selectedModel = (LlamaModel) llamaModelComboBoxModel.getSelectedItem();
var models = selectedModel.filterSelectedModelsBySize(
(ModelSize) modelSizeComboBoxModel.getSelectedItem());
comboBox.setEnabled(
modelSizeComboBoxModel.getSize() > 1 && !llamaServerAgent.isServerRunning());
if (!models.isEmpty()) {
huggingFaceComboBoxModel.removeAllElements();
huggingFaceComboBoxModel.addAll(models);
huggingFaceComboBoxModel.setSelectedItem(models.get(0));
}
});
comboBox.addItemListener(e -> handleModelSizeSelection(
e, llamaModelComboBoxModel, modelSizeComboBoxModel, llamaServerAgent));
return comboBox;
}
private ComboBox<HuggingFaceModel> createModelQuantizationComboBox(
DefaultComboBoxModel<HuggingFaceModel> huggingFaceComboBoxModel) {
private void handleModelSizeSelection(
java.awt.event.ItemEvent e,
ComboBoxModel<LlamaModel> llamaModelComboBoxModel,
DefaultComboBoxModel<ModelSize> modelSizeComboBoxModel,
LlamaServerAgent llamaServerAgent) {
var selectedModel = (LlamaModel) llamaModelComboBoxModel.getSelectedItem();
if (selectedModel == null) {
return;
}
var selectedSize = (ModelSize) modelSizeComboBoxModel.getSelectedItem();
if (selectedSize == null) {
return;
}
var models = selectedModel.filterSelectedModelsBySize(selectedSize);
modelSizeComboBox.setEnabled(
modelSizeComboBoxModel.getSize() > 1 && !llamaServerAgent.isServerRunning());
if (!models.isEmpty()) {
populateModelComboBoxWithGroups(models);
huggingFaceComboBoxModel.setSelectedItem(models.get(0));
}
}
private ComboBox<Object> createModelQuantizationComboBox() {
var comboBox = new ComboBox<>(huggingFaceComboBoxModel);
updateFromModelState(comboBox.getItem());
comboBox.addItemListener(e -> updateFromModelState((HuggingFaceModel) e.getItem()));
comboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
var item = value instanceof HuggingFaceModel hfm ? hfm.getQuantizationLabel() : value;
return super.getListCellRendererComponent(list, item, index, isSelected, cellHasFocus);
}
});
var selectedItem = comboBox.getSelectedItem();
if (selectedItem instanceof HuggingFaceModel) {
updateFromModelState((HuggingFaceModel) selectedItem);
}
comboBox.addItemListener(this::handleQuantizationSelection);
comboBox.setRenderer(new ModelQuantizationRenderer());
return comboBox;
}
private void handleQuantizationSelection(java.awt.event.ItemEvent e) {
var item = e.getItem();
if (item instanceof HuggingFaceModel hfm) {
updateFromModelState(hfm);
} else if (item instanceof String) {
SwingUtilities.invokeLater(this::selectFirstAvailableModel);
}
}
private void selectFirstAvailableModel() {
for (int i = 0; i < huggingFaceComboBoxModel.getSize(); i++) {
var item = huggingFaceComboBoxModel.getElementAt(i);
if (item instanceof HuggingFaceModel) {
huggingFaceModelComboBox.setSelectedItem(item);
break;
}
}
}
private void updateFromModelState(HuggingFaceModel selectedModel) {
var modelExists = isModelExists(selectedModel);
updateModelHelpTooltip(selectedModel);
modelDetailsLabel.setText(getHuggingFaceModelDetailsHtml(selectedModel));
modelExistsIcon.setVisible(modelExists);
downloadModelActionLinkWrapper.setVisible(!modelExists);
updateModelActionsPanel(selectedModel);
}
private TextFieldWithBrowseButton createBrowsableCustomModelTextField(boolean enabled) {
@ -403,7 +508,6 @@ public class LlamaModelPreferencesForm {
private AnActionLink createCancelDownloadLink(
JBLabel progressLabel,
JPanel actionLinkWrapper,
DefaultComboBoxModel<HuggingFaceModel> huggingFaceComboBoxModel,
ProgressIndicator progressIndicator) {
return new AnActionLink(
CodeGPTBundle.get("settingsConfigurable.service.llama.cancelDownloadLink.label"),
@ -414,10 +518,7 @@ public class LlamaModelPreferencesForm {
configureFieldsForDownloading(false);
updateActionLink(
actionLinkWrapper,
createDownloadModelLink(
progressLabel,
actionLinkWrapper,
huggingFaceComboBoxModel));
createDownloadModelLink(progressLabel, actionLinkWrapper));
progressIndicator.cancel();
});
}
@ -426,7 +527,11 @@ public class LlamaModelPreferencesForm {
private void updateActionLink(JPanel actionLinkWrapper, AnActionLink actionLink) {
actionLinkWrapper.removeAll();
actionLinkWrapper.add(actionLink, BorderLayout.WEST);
var flowPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
flowPanel.add(actionLink);
flowPanel.add(Box.createHorizontalStrut(16));
flowPanel.add(createOpenFolderLink());
actionLinkWrapper.add(flowPanel, BorderLayout.WEST);
actionLinkWrapper.revalidate();
actionLinkWrapper.repaint();
}
@ -437,13 +542,11 @@ public class LlamaModelPreferencesForm {
modelComboBox.setEnabled(!downloading);
modelSizeComboBox.setEnabled(!downloading);
huggingFaceModelComboBox.setEnabled(!downloading);
modelExistsIcon.setVisible(!downloading);
}
private AnActionLink createDownloadModelLink(
JBLabel progressLabel,
JPanel actionLinkWrapper,
DefaultComboBoxModel<HuggingFaceModel> huggingFaceComboBoxModel) {
JPanel actionLinkWrapper) {
return new AnActionLink(
CodeGPTBundle.get("settingsConfigurable.service.llama.downloadModelLink.label"),
new DownloadModelAction(
@ -451,29 +554,26 @@ public class LlamaModelPreferencesForm {
configureFieldsForDownloading(true);
updateActionLink(
actionLinkWrapper,
createCancelDownloadLink(
progressLabel,
actionLinkWrapper,
huggingFaceComboBoxModel,
progressIndicator));
createCancelDownloadLink(progressLabel, actionLinkWrapper, progressIndicator));
}),
() -> SwingUtilities.invokeLater(() -> {
configureFieldsForDownloading(false);
updateActionLink(
actionLinkWrapper,
createDownloadModelLink(
progressLabel,
actionLinkWrapper,
huggingFaceComboBoxModel));
actionLinkWrapper.setVisible(false);
LlamaSettings.getCurrentState().setHuggingFaceModel(
(HuggingFaceModel) huggingFaceComboBoxModel.getSelectedItem());
var downloadedModel = getSelectedModel();
if (downloadedModel != null) {
LlamaSettings.getCurrentState().setHuggingFaceModel(downloadedModel);
updateFromModelState(downloadedModel);
}
}),
(error) -> {
throw new RuntimeException(error);
},
(text) -> SwingUtilities.invokeLater(() -> progressLabel.setText(text)),
huggingFaceComboBoxModel), "unknown");
getHuggingFaceComboBoxModel()), "unknown");
}
@SuppressWarnings("unchecked")
private DefaultComboBoxModel<HuggingFaceModel> getHuggingFaceComboBoxModel() {
return (DefaultComboBoxModel<HuggingFaceModel>) (DefaultComboBoxModel<?>) huggingFaceComboBoxModel;
}
private void updateModelHelpTooltip(HuggingFaceModel model) {
@ -488,6 +588,131 @@ public class LlamaModelPreferencesForm {
.installOn(helpIcon);
}
private record ModelDetails(double fileSize, double maxRAMRequired) {
private void populateModelComboBoxWithGroups(List<HuggingFaceModel> models) {
huggingFaceComboBoxModel.removeAllElements();
var downloadedModels = models.stream()
.filter(LlamaSettings::isModelExists)
.toList();
var notDownloadedModels = models.stream()
.filter(model -> !isModelExists(model))
.toList();
if (!downloadedModels.isEmpty()) {
huggingFaceComboBoxModel.addElement(GROUP_DOWNLOADED);
downloadedModels.forEach(huggingFaceComboBoxModel::addElement);
}
if (!notDownloadedModels.isEmpty()) {
huggingFaceComboBoxModel.addElement(GROUP_NOT_DOWNLOADED);
notDownloadedModels.forEach(huggingFaceComboBoxModel::addElement);
}
}
}
private void updateModelActionsPanel(HuggingFaceModel model) {
modelActionsWrapper.removeAll();
downloadModelActionLinkWrapper.removeAll();
var flowPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
if (isModelExists(model)) {
flowPanel.add(createDeleteModelLink(model));
} else {
flowPanel.add(createDownloadModelLink(progressLabel, downloadModelActionLinkWrapper));
}
flowPanel.add(Box.createHorizontalStrut(16));
flowPanel.add(createOpenFolderLink());
downloadModelActionLinkWrapper.setVisible(false);
modelActionsWrapper.setVisible(true);
modelActionsWrapper.add(flowPanel, BorderLayout.WEST);
modelActionsWrapper.revalidate();
modelActionsWrapper.repaint();
downloadModelActionLinkWrapper.revalidate();
downloadModelActionLinkWrapper.repaint();
}
private AnActionLink createDeleteModelLink(HuggingFaceModel model) {
return new AnActionLink("Delete Model", new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
var modelName = model.getFileName();
var result = Messages.showYesNoDialog(
"Are you sure you want to delete the model '" + modelName + "'?",
"Delete Model",
Messages.getQuestionIcon()
);
if (result == Messages.YES) {
var modelFile = getLlamaModelsPath().resolve(modelName).toFile();
if (modelFile.exists() && modelFile.delete()) {
updateFromModelState(model);
Messages.showInfoMessage("Model '" + modelName + "' has been deleted.",
"Model Deleted");
} else {
Messages.showErrorDialog("Failed to delete the model file.", "Delete Failed");
}
}
}
});
}
private AnActionLink createOpenFolderLink() {
return new AnActionLink("Open in Folder", new AnAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
try {
var modelsPath = getLlamaModelsPath().toFile();
if (!modelsPath.exists() && !modelsPath.mkdirs()) {
Messages.showErrorDialog("Failed to create models directory.", "Error");
return;
}
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(modelsPath);
} else {
Messages.showErrorDialog("Desktop operations are not supported on this system.",
"Error");
}
} catch (IOException ex) {
Messages.showErrorDialog("Failed to open the models folder: " + ex.getMessage(), "Error");
}
}
});
}
private static class ModelQuantizationRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
if (value instanceof String groupHeader) {
var label = (JLabel) super.getListCellRendererComponent(list, groupHeader, index, false,
false);
label.setFont(label.getFont().deriveFont(java.awt.Font.BOLD));
label.setEnabled(false);
if (index > 0) {
label.setBorder(JBUI.Borders.compound(
JBUI.Borders.customLine(JBUI.CurrentTheme.Popup.separatorColor(), 1, 0, 0, 0),
JBUI.Borders.empty(4, 4)
));
} else {
label.setBorder(JBUI.Borders.empty(4, 4));
}
return label;
}
if (value instanceof HuggingFaceModel hfm) {
var item = hfm.getQuantizationLabel();
return super.getListCellRendererComponent(list, item, index, isSelected, cellHasFocus);
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
}
private record ModelDetails(double fileSize, double maxRAMRequired) {
}
}

View file

@ -1,87 +0,0 @@
package ee.carlrobert.codegpt.settings.service.llama.form;
import com.intellij.openapi.ui.panel.ComponentPanelBuilder;
import com.intellij.ui.components.JBTextField;
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.settings.service.llama.LlamaSettingsState;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class LlamaRequestPreferencesForm {
private final IntegerField topKField;
private final JBTextField topPField;
private final JBTextField minPField;
private final JBTextField repeatPenaltyField;
public LlamaRequestPreferencesForm(LlamaSettingsState llamaSettings) {
topKField = new IntegerField();
topKField.setColumns(12);
topKField.setValue(llamaSettings.getTopK());
topPField = new JBTextField(12);
topPField.setText(String.valueOf(llamaSettings.getTopP()));
minPField = new JBTextField(12);
minPField.setText(String.valueOf(llamaSettings.getMinP()));
repeatPenaltyField = new JBTextField(12);
repeatPenaltyField.setText(String.valueOf(llamaSettings.getRepeatPenalty()));
}
public JPanel getForm() {
return FormBuilder.createFormBuilder()
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.topK.label"),
topKField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.topK.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.topP.label"),
topPField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.topP.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.minP.label"),
minPField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.minP.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.repeatPenalty.label"),
repeatPenaltyField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.repeatPenalty.comment"))
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
public void resetForm(LlamaSettingsState state) {
topKField.setValue(state.getTopK());
topPField.setText(String.valueOf((state.getTopP())));
minPField.setText(String.valueOf((state.getMinP())));
repeatPenaltyField.setText(String.valueOf((state.getRepeatPenalty())));
}
public int getTopK() {
return topKField.getValue();
}
public double getTopP() {
return Double.parseDouble(topPField.getText());
}
public double getMinP() {
return Double.parseDouble(minPField.getText());
}
public double getRepeatPenalty() {
return Double.parseDouble(repeatPenaltyField.getText());
}
private JLabel createComment(String messageKey) {
var comment = ComponentPanelBuilder.createCommentComponent(
CodeGPTBundle.get(messageKey), true);
comment.setBorder(JBUI.Borders.empty(0, 4));
return comment;
}
}

View file

@ -1,404 +0,0 @@
package ee.carlrobert.codegpt.settings.service.llama.form;
import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LlamaApiKey;
import static ee.carlrobert.codegpt.settings.service.llama.LlamaSettings.isModelExists;
import static ee.carlrobert.codegpt.ui.UIUtil.createComment;
import static ee.carlrobert.codegpt.ui.UIUtil.createForm;
import static ee.carlrobert.codegpt.ui.UIUtil.withEmptyLeftBorder;
import com.intellij.icons.AllIcons.Actions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.SystemInfoRt;
import com.intellij.ui.PortField;
import com.intellij.ui.TitledSeparator;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBPasswordField;
import com.intellij.ui.components.JBRadioButton;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.fields.IntegerField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UI;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
import ee.carlrobert.codegpt.completions.llama.LlamaServerAgent;
import ee.carlrobert.codegpt.completions.llama.LlamaServerStartupParams;
import ee.carlrobert.codegpt.completions.llama.PromptTemplate;
import ee.carlrobert.codegpt.credentials.CredentialsStore;
import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey;
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettingsState;
import ee.carlrobert.codegpt.ui.OverlayUtil;
import ee.carlrobert.codegpt.ui.UIUtil;
import ee.carlrobert.codegpt.ui.UIUtil.RadioButtonWithLayout;
import ee.carlrobert.codegpt.ui.URLTextField;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import org.jetbrains.annotations.Nullable;
public class LlamaServerPreferencesForm {
private static final String RUN_LOCAL_SERVER_FORM_CARD_CODE = "RunLocalServerSettings";
private static final String USE_EXISTING_SERVER_FORM_CARD_CODE = "UseExistingServerSettings";
private final LlamaModelPreferencesForm llamaModelPreferencesForm;
private final JBRadioButton runLocalServerRadioButton;
private final JBRadioButton useExistingServerRadioButton;
private final JBTextField baseHostField;
private final JBPasswordField apiKeyField;
private final PortField portField;
private final IntegerField maxTokensField;
private final IntegerField threadsField;
private final JBTextField additionalParametersField;
private final JBTextField additionalBuildParametersField;
private final JBTextField additionalEnvironmentVariablesField;
private final ChatPromptTemplatePanel remotePromptTemplatePanel;
private final InfillPromptTemplatePanel infillPromptTemplatePanel;
public LlamaServerPreferencesForm(LlamaSettingsState settings) {
var llamaServerAgent = ApplicationManager.getApplication().getService(LlamaServerAgent.class);
var serverRunning = llamaServerAgent.isServerRunning();
portField = new PortField(settings.getServerPort());
portField.setEnabled(!serverRunning);
maxTokensField = new IntegerField("max_tokens", 256, 4096);
maxTokensField.setColumns(12);
maxTokensField.setValue(settings.getContextSize());
maxTokensField.setEnabled(!serverRunning);
threadsField = new IntegerField("threads", 1, 256);
threadsField.setColumns(12);
threadsField.setValue(settings.getThreads());
threadsField.setEnabled(!serverRunning);
additionalParametersField = new JBTextField(settings.getAdditionalParameters(), 30);
additionalParametersField.setEnabled(!serverRunning);
additionalBuildParametersField = new JBTextField(settings.getAdditionalBuildParameters(), 30);
additionalBuildParametersField.setEnabled(!serverRunning);
additionalEnvironmentVariablesField = new JBTextField(
settings.getAdditionalEnvironmentVariables(), 30);
additionalEnvironmentVariablesField.setEnabled(!serverRunning);
baseHostField = new URLTextField(settings.getBaseHost(), 30);
apiKeyField = new JBPasswordField();
apiKeyField.setColumns(30);
ApplicationManager.getApplication().executeOnPooledThread(() -> {
var apiKey = CredentialsStore.getCredential(CredentialKey.LlamaApiKey.INSTANCE);
SwingUtilities.invokeLater(() -> apiKeyField.setText(apiKey));
});
llamaModelPreferencesForm = new LlamaModelPreferencesForm();
runLocalServerRadioButton = new JBRadioButton("Run local server",
settings.isRunLocalServer());
useExistingServerRadioButton = new JBRadioButton("Use remote server",
!settings.isRunLocalServer());
runLocalServerRadioButton.setEnabled(SystemInfoRt.isUnix);
runLocalServerRadioButton.setVisible(SystemInfoRt.isUnix);
remotePromptTemplatePanel = new ChatPromptTemplatePanel(
settings.getRemoteModelPromptTemplate(), true);
infillPromptTemplatePanel = new InfillPromptTemplatePanel(
settings.getRemoteModelInfillPromptTemplate(), true
);
}
public JPanel getForm() {
var llamaServerAgent =
ApplicationManager.getApplication().getService(LlamaServerAgent.class);
return createForm(Map.of(
RUN_LOCAL_SERVER_FORM_CARD_CODE, new RadioButtonWithLayout(runLocalServerRadioButton,
createRunLocalServerForm(llamaServerAgent)),
USE_EXISTING_SERVER_FORM_CARD_CODE, new RadioButtonWithLayout(useExistingServerRadioButton,
createUseExistingServerForm())
), SystemInfoRt.isUnix ? (runLocalServerRadioButton.isSelected()
? RUN_LOCAL_SERVER_FORM_CARD_CODE
: USE_EXISTING_SERVER_FORM_CARD_CODE) : USE_EXISTING_SERVER_FORM_CARD_CODE);
}
public void resetForm(LlamaSettingsState state) {
llamaModelPreferencesForm.resetForm(state);
remotePromptTemplatePanel.setPromptTemplate(state.getLocalModelPromptTemplate()); // ?
infillPromptTemplatePanel.setPromptTemplate(state.getLocalModelInfillPromptTemplate());
runLocalServerRadioButton.setSelected(state.isRunLocalServer());
baseHostField.setText(state.getBaseHost());
portField.setNumber(state.getServerPort());
maxTokensField.setValue(state.getContextSize());
threadsField.setValue(state.getThreads());
additionalParametersField.setText(state.getAdditionalParameters());
additionalBuildParametersField.setText(state.getAdditionalBuildParameters());
additionalEnvironmentVariablesField.setText(state.getAdditionalEnvironmentVariables());
remotePromptTemplatePanel.setPromptTemplate(state.getRemoteModelPromptTemplate()); // ?
infillPromptTemplatePanel.setPromptTemplate(state.getRemoteModelInfillPromptTemplate());
apiKeyField.setText(CredentialsStore.getCredential(LlamaApiKey.INSTANCE));
}
public JComponent createUseExistingServerForm() {
var apiKeyFieldPanel = UI.PanelFactory.panel(apiKeyField)
.withLabel(CodeGPTBundle.get("settingsConfigurable.shared.apiKey.label"))
.resizeX(false)
.withComment(
CodeGPTBundle.get("settingsConfigurable.shared.apiKey.comment"))
.withCommentHyperlinkListener(UIUtil::handleHyperlinkClicked)
.createPanel();
return withEmptyLeftBorder(FormBuilder.createFormBuilder()
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.baseHost.label"),
baseHostField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.baseHost.comment"))
.addLabeledComponent(CodeGPTBundle.get("shared.promptTemplate"),
remotePromptTemplatePanel)
.addComponentToRightColumn(remotePromptTemplatePanel.getPromptTemplateHelpText())
.addLabeledComponent(CodeGPTBundle.get("shared.infillPromptTemplate"),
infillPromptTemplatePanel)
.addComponentToRightColumn(infillPromptTemplatePanel.getPromptTemplateHelpText())
.addComponent(new TitledSeparator(
CodeGPTBundle.get("settingsConfigurable.shared.authentication.title")))
.addComponent(withEmptyLeftBorder(apiKeyFieldPanel))
.getPanel());
}
public JComponent createRunLocalServerForm(LlamaServerAgent llamaServerAgent) {
var serverProgressPanel = new ServerProgressPanel();
serverProgressPanel.setBorder(JBUI.Borders.emptyRight(16));
return withEmptyLeftBorder(FormBuilder.createFormBuilder()
.addComponent(new TitledSeparator(
CodeGPTBundle.get("settingsConfigurable.service.llama.modelPreferences.title")))
.addComponent(withEmptyLeftBorder(llamaModelPreferencesForm.getForm()))
.addComponent(new TitledSeparator("Server Configuration"))
.addComponent(withEmptyLeftBorder(FormBuilder.createFormBuilder()
.addLabeledComponent(
CodeGPTBundle.get("shared.port"),
JBUI.Panels.simplePanel()
.addToLeft(portField)
.addToRight(JBUI.Panels.simplePanel()
.addToCenter(serverProgressPanel)
.addToRight(getServerButton(llamaServerAgent, serverProgressPanel))))
.addVerticalGap(4)
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.contextSize.label"),
maxTokensField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.contextSize.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.threads.label"),
threadsField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.threads.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalParameters.label"),
additionalParametersField)
.addComponentToRightColumn(
createComment(
"settingsConfigurable.service.llama.additionalParameters.comment"))
.addLabeledComponent(
CodeGPTBundle.get(
"settingsConfigurable.service.llama.additionalBuildParameters.label"),
additionalBuildParametersField)
.addComponentToRightColumn(
createComment(
"settingsConfigurable.service.llama.additionalBuildParameters.comment"))
.addVerticalGap(4)
.addLabeledComponent(
CodeGPTBundle.get(
"settingsConfigurable.service.llama.additionalEnvironmentVariables.label"),
additionalEnvironmentVariablesField)
.addComponentToRightColumn(
createComment(
"settingsConfigurable.service.llama.additionalEnvironmentVariables.comment"))
.addVerticalGap(4)
.addComponentFillVertically(new JPanel(), 0)
.getPanel()))
.getPanel());
}
private JButton getServerButton(
LlamaServerAgent llamaServerAgent,
ServerProgressPanel serverProgressPanel) {
llamaServerAgent.setActiveServerProgressPanel(serverProgressPanel);
var serverRunning = llamaServerAgent.isServerRunning();
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 (!validateModelConfiguration()) {
return;
}
if (llamaServerAgent.isServerRunning()) {
enableForm(serverButton, serverProgressPanel);
llamaServerAgent.stopAgent();
} else {
disableForm(serverButton, serverProgressPanel);
llamaServerAgent.startAgent(
new LlamaServerStartupParams(
llamaModelPreferencesForm.getActualModelPath(),
getContextSize(),
getThreads(),
getServerPort(),
getListOfAdditionalParameters(),
getListOfAdditionalBuildParameters(),
getMapOfAdditionalEnvironmentVariables()
),
serverProgressPanel,
() -> {
setFormEnabled(false);
serverProgressPanel.displayComponent(new JBLabel(
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.serverRunning"),
Actions.Checked,
SwingConstants.LEADING));
},
(activeServerProgressPanel) -> {
setFormEnabled(true);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(Actions.Execute);
activeServerProgressPanel.displayComponent(new JBLabel(
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.serverStopped"),
Actions.Cancel,
SwingConstants.LEADING));
});
}
});
return serverButton;
}
private boolean validateModelConfiguration() {
return validateCustomModelPath() && validateSelectedModel();
}
private boolean validateCustomModelPath() {
if (llamaModelPreferencesForm.isUseCustomLlamaModel()) {
var customModelPath = llamaModelPreferencesForm.getCustomLlamaModelPath();
if (customModelPath == null || customModelPath.isEmpty()) {
OverlayUtil.showBalloon(
CodeGPTBundle.get("validation.error.fieldRequired"),
MessageType.ERROR,
llamaModelPreferencesForm.getBrowsableCustomModelTextField());
return false;
}
}
return true;
}
private boolean validateSelectedModel() {
if (!llamaModelPreferencesForm.isUseCustomLlamaModel()
&& !isModelExists(llamaModelPreferencesForm.getSelectedModel())) {
OverlayUtil.showBalloon(
CodeGPTBundle.get("settingsConfigurable.service.llama.overlay.modelNotDownloaded.text"),
MessageType.ERROR,
llamaModelPreferencesForm.getHuggingFaceModelComboBox());
return false;
}
return true;
}
private void enableForm(JButton serverButton, ServerProgressPanel progressPanel) {
setFormEnabled(true);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(Actions.Execute);
progressPanel.displayText(
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.stoppingServer"));
}
private void disableForm(JButton serverButton, ServerProgressPanel progressPanel) {
setFormEnabled(false);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label"));
serverButton.setIcon(Actions.Suspend);
progressPanel.displayText(
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.startingServer"));
}
private void setFormEnabled(boolean enabled) {
llamaModelPreferencesForm.enableFields(enabled);
portField.setEnabled(enabled);
maxTokensField.setEnabled(enabled);
threadsField.setEnabled(enabled);
additionalParametersField.setEnabled(enabled);
additionalBuildParametersField.setEnabled(enabled);
additionalEnvironmentVariablesField.setEnabled(enabled);
}
public boolean isRunLocalServer() {
return runLocalServerRadioButton.isSelected();
}
public String getBaseHost() {
return baseHostField.getText();
}
public int getServerPort() {
return portField.getNumber();
}
public LlamaModelPreferencesForm getLlamaModelPreferencesForm() {
return llamaModelPreferencesForm;
}
public int getContextSize() {
return maxTokensField.getValue();
}
public void setThreads(int threads) {
threadsField.setValue(threads);
}
public int getThreads() {
return threadsField.getValue();
}
public String getAdditionalParameters() {
return additionalParametersField.getText();
}
public List<String> getListOfAdditionalParameters() {
return LlamaSettings.getAdditionalParametersList(additionalParametersField.getText());
}
public String getAdditionalBuildParameters() {
return additionalBuildParametersField.getText();
}
public List<String> getListOfAdditionalBuildParameters() {
return LlamaSettings.getAdditionalParametersList(additionalBuildParametersField.getText());
}
public String getAdditionalEnvironmentVariables() {
return additionalEnvironmentVariablesField.getText();
}
public Map<String, String> getMapOfAdditionalEnvironmentVariables() {
return LlamaSettings.getAdditionalEnvironmentVariablesMap(
additionalEnvironmentVariablesField.getText());
}
public PromptTemplate getPromptTemplate() {
var template = isRunLocalServer() ? llamaModelPreferencesForm.getPromptTemplate()
: remotePromptTemplatePanel.getPromptTemplate();
return template == null ? PromptTemplate.CODE_QWEN : template;
}
public @Nullable String getApiKey() {
var apiKey = new String(apiKeyField.getPassword());
return apiKey.isEmpty() ? null : apiKey;
}
public InfillPromptTemplate getInfillPromptTemplate() {
return infillPromptTemplatePanel.getPromptTemplate();
}
}

View file

@ -1,83 +1,456 @@
package ee.carlrobert.codegpt.settings.service.llama.form;
import static ee.carlrobert.codegpt.ui.UIUtil.createComment;
import static ee.carlrobert.codegpt.ui.UIUtil.withEmptyLeftBorder;
import com.intellij.ui.TitledSeparator;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.ui.JBColor;
import com.intellij.ui.PortField;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.fields.IntegerField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.AsyncProcessIcon;
import com.intellij.util.ui.components.BorderLayoutPanel;
import ee.carlrobert.codegpt.CodeGPTBundle;
import ee.carlrobert.codegpt.settings.service.CodeCompletionConfigurationForm;
import ee.carlrobert.codegpt.completions.llama.LlamaServerAgent;
import ee.carlrobert.codegpt.completions.llama.LlamaServerStartupParams;
import ee.carlrobert.codegpt.completions.llama.SimpleConsolePanel;
import ee.carlrobert.codegpt.completions.llama.logging.SettingsFormLoggingStrategy;
import ee.carlrobert.codegpt.services.llama.ServerLogsManager;
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings;
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettingsState;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import org.jetbrains.annotations.NotNull;
public class LlamaSettingsForm extends JPanel {
private final LlamaServerPreferencesForm llamaServerPreferencesForm;
private final LlamaRequestPreferencesForm llamaRequestPreferencesForm;
private final CodeCompletionConfigurationForm codeCompletionConfigurationForm;
private static final int SERVER_CONFIG_TAB = 0;
private static final int SERVER_LOGS_TAB = 1;
private static final int BUILD_OUTPUT_TAB = 2;
private static final String SERVER_LOGS_DISABLED_TOOLTIP = "Server must be running to view logs";
private static final String BUILD_OUTPUT_DISABLED_TOOLTIP = "Available during build process";
public LlamaSettingsForm(LlamaSettingsState settings) {
llamaServerPreferencesForm = new LlamaServerPreferencesForm(settings);
llamaRequestPreferencesForm = new LlamaRequestPreferencesForm(settings);
codeCompletionConfigurationForm = new CodeCompletionConfigurationForm(
settings.isCodeCompletionsEnabled(),
null,
null);
init();
private final LlamaServerAgent serverAgent;
private final LlamaSettingsState settingsState;
private final JBTabbedPane tabbedPane;
private final LlamaServerPreferencesForm serverPreferencesForm;
private final SimpleConsolePanel serverLogsConsole;
private final SimpleConsolePanel buildLogsConsole;
private final JPanel serverStatusPanel;
private final JBLabel serverStatusLabel;
private final AsyncProcessIcon serverStatusSpinner;
public LlamaSettingsForm(LlamaSettingsState settingsState) {
this.settingsState = settingsState;
serverAgent = ApplicationManager.getApplication().getService(LlamaServerAgent.class);
tabbedPane = new JBTabbedPane();
serverStatusPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
serverStatusLabel = new JBLabel();
serverStatusSpinner = new AsyncProcessIcon("server_status_spinner");
serverStatusPanel.add(serverStatusSpinner);
serverStatusPanel.add(Box.createHorizontalStrut(4));
serverStatusPanel.add(serverStatusLabel);
serverStatusSpinner.setVisible(false);
serverPreferencesForm = new LlamaServerPreferencesForm(settingsState, this);
serverLogsConsole = new SimpleConsolePanel();
buildLogsConsole = new SimpleConsolePanel();
updateServerStatus();
loadExistingLogs();
setLayout(new BorderLayout());
add(createLocalServerPanel(), BorderLayout.CENTER);
serverAgent.setSettingsForm(this);
}
private JPanel createLocalServerPanel() {
var panel = new BorderLayoutPanel();
var modelPreferencesForm = serverPreferencesForm.getLlamaModelPreferencesForm();
var modelPanel = new BorderLayoutPanel();
modelPanel.add(modelPreferencesForm.getForm(), BorderLayout.CENTER);
modelPanel.setBorder(JBUI.Borders.emptyBottom(8));
panel.add(modelPanel, BorderLayout.NORTH);
var serverConfigTab = createServerConfigurationTab();
tabbedPane.addTab(CodeGPTBundle.get("llama.ui.tab.serverConfiguration"), AllIcons.General.Settings, serverConfigTab);
var serverLogsTab = createServerLogsTab();
tabbedPane.addTab(CodeGPTBundle.get("llama.ui.tab.serverLogs"), AllIcons.Debugger.Console, serverLogsTab);
var buildLogsTab = createBuildLogsTab();
tabbedPane.addTab(CodeGPTBundle.get("llama.ui.tab.buildOutput"), AllIcons.Actions.Compile, buildLogsTab);
tabbedPane.addChangeListener(e -> {
SwingUtilities.invokeLater(() -> {
int selectedIndex = tabbedPane.getSelectedIndex();
if (selectedIndex == 1) {
serverLogsConsole.revalidate();
serverLogsConsole.repaint();
} else if (selectedIndex == 2) {
buildLogsConsole.revalidate();
buildLogsConsole.repaint();
}
});
});
panel.add(tabbedPane, BorderLayout.CENTER);
setTabState(SERVER_LOGS_TAB, serverAgent.isServerRunning(), SERVER_LOGS_DISABLED_TOOLTIP);
setTabState(BUILD_OUTPUT_TAB, serverAgent.isBuildInProgress(), BUILD_OUTPUT_DISABLED_TOOLTIP);
return panel;
}
private JPanel createServerConfigurationTab() {
var serverRunning = serverAgent.isServerRunning();
var portField = new PortField(serverPreferencesForm.getServerPort());
portField.setEnabled(!serverRunning);
var contextSizeField = new IntegerField("context_size", 256, 4096);
contextSizeField.setColumns(12);
contextSizeField.setValue(serverPreferencesForm.getContextSize());
contextSizeField.setEnabled(!serverRunning);
var threadsField = new IntegerField("threads", 1, 256);
threadsField.setColumns(12);
threadsField.setValue(serverPreferencesForm.getThreads());
threadsField.setEnabled(!serverRunning);
var additionalParametersField = new JBTextField(serverPreferencesForm.getAdditionalParameters(),
30);
additionalParametersField.setEnabled(!serverRunning);
var additionalBuildParametersField = new JBTextField(
serverPreferencesForm.getAdditionalBuildParameters(), 30);
additionalBuildParametersField.setEnabled(!serverRunning);
var additionalEnvironmentVariablesField = new JBTextField(
serverPreferencesForm.getAdditionalEnvironmentVariables(), 30);
additionalEnvironmentVariablesField.setEnabled(!serverRunning);
var config = new ServerButtonConfig(
portField,
contextSizeField,
threadsField,
additionalParametersField,
additionalBuildParametersField,
additionalEnvironmentVariablesField
);
var serverButton = createServerButton(config);
var portPanel = new JPanel();
portPanel.setLayout(new BoxLayout(portPanel, BoxLayout.X_AXIS));
portPanel.add(portField);
portPanel.add(Box.createHorizontalGlue());
portPanel.add(serverButton);
var form = withEmptyLeftBorder(FormBuilder.createFormBuilder()
.addVerticalGap(8)
.addLabeledComponent(CodeGPTBundle.get("shared.port"), portPanel)
.addVerticalGap(8)
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.contextSize.label"),
contextSizeField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.contextSize.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.threads.label"),
threadsField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.threads.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalParameters.label"),
additionalParametersField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.additionalParameters.comment"))
.addLabeledComponent(
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalBuildParameters.label"),
additionalBuildParametersField)
.addComponentToRightColumn(
createComment("settingsConfigurable.service.llama.additionalBuildParameters.comment"))
.addLabeledComponent(
CodeGPTBundle.get(
"settingsConfigurable.service.llama.additionalEnvironmentVariables.label"),
additionalEnvironmentVariablesField)
.addComponentToRightColumn(
createComment(
"settingsConfigurable.service.llama.additionalEnvironmentVariables.comment"))
.addComponentFillVertically(new JPanel(), 0)
.getPanel());
var panel = new JPanel(new BorderLayout());
panel.add(form, BorderLayout.CENTER);
return panel;
}
private JButton createServerButton(ServerButtonConfig config) {
var serverRunning = serverAgent.isServerRunning();
var buildInProgress = serverAgent.isBuildInProgress();
var serverButton = new JButton();
if (serverRunning) {
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label"));
serverButton.setIcon(AllIcons.Actions.Suspend);
} else if (buildInProgress) {
serverButton.setText(CodeGPTBundle.get("llama.ui.button.stopBuild"));
serverButton.setIcon(AllIcons.Actions.Suspend);
} else {
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(AllIcons.Actions.Execute);
}
serverButton.addActionListener(e -> {
if (serverAgent.isServerRunning()) {
serverAgent.stopAgent();
setFieldsEnabled(true, config);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(AllIcons.Actions.Execute);
} else if (serverAgent.isBuildInProgress()) {
serverAgent.stopAgent();
setFieldsEnabled(true, config);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(AllIcons.Actions.Execute);
} else {
setTabState(BUILD_OUTPUT_TAB, true, BUILD_OUTPUT_DISABLED_TOOLTIP);
tabbedPane.setSelectedIndex(BUILD_OUTPUT_TAB);
serverButton.setText(CodeGPTBundle.get("llama.ui.button.stopBuild"));
serverButton.setIcon(AllIcons.Actions.Suspend);
setFieldsEnabled(false, config);
logToConsole(CodeGPTBundle.get("llama.process.startingBuild"), false, true);
var params = new LlamaServerStartupParams(
serverPreferencesForm.getLlamaModelPreferencesForm().getActualModelPath(),
config.getContextSizeField().getValue(),
config.getThreadsField().getValue(),
config.getPortField().getNumber(),
LlamaSettings.getAdditionalParametersList(
config.getAdditionalParametersField().getText()),
LlamaSettings.getAdditionalParametersList(
config.getAdditionalBuildParametersField().getText()),
LlamaSettings.getAdditionalEnvironmentVariablesMap(
config.getAdditionalEnvironmentVariablesField().getText())
);
serverAgent.startAgent(
params,
new SettingsFormLoggingStrategy(this),
() -> {
SwingUtilities.invokeLater(() -> {
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label"));
serverButton.setIcon(AllIcons.Actions.Suspend);
setTabState(SERVER_LOGS_TAB, true, SERVER_LOGS_DISABLED_TOOLTIP);
setTabState(BUILD_OUTPUT_TAB, false, BUILD_OUTPUT_DISABLED_TOOLTIP);
tabbedPane.setSelectedIndex(SERVER_LOGS_TAB);
});
},
() -> {
SwingUtilities.invokeLater(() -> {
setFieldsEnabled(true, config);
serverButton.setText(
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
serverButton.setIcon(AllIcons.Actions.Execute);
});
}
);
}
});
return serverButton;
}
private void setFieldsEnabled(boolean enabled, ServerButtonConfig config) {
config.getPortField().setEnabled(enabled);
config.getContextSizeField().setEnabled(enabled);
config.getThreadsField().setEnabled(enabled);
config.getAdditionalParametersField().setEnabled(enabled);
config.getAdditionalBuildParametersField().setEnabled(enabled);
config.getAdditionalEnvironmentVariablesField().setEnabled(enabled);
}
private JPanel createBuildLogsTab() {
return createLogsTab(buildLogsConsole, false);
}
private JPanel createServerLogsTab() {
return createLogsTab(serverLogsConsole, true);
}
private JPanel createLogsTab(Component view, boolean isServerLogs) {
var panel = new JPanel(new BorderLayout());
panel.add(createLogsToolbar(isServerLogs), BorderLayout.NORTH);
var scrollPane = new JScrollPane(view);
scrollPane.setPreferredSize(JBUI.size(600, 240));
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(createStatusBar(), BorderLayout.SOUTH);
return panel;
}
private JComponent createLogsToolbar(boolean isServerLogs) {
var actionGroup = new DefaultActionGroup();
actionGroup.add(new DumbAwareAction(CodeGPTBundle.get("llama.ui.action.clear"), CodeGPTBundle.get("llama.ui.action.clear.description"), AllIcons.Actions.GC) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
var consolePanel = isServerLogs ? serverLogsConsole : buildLogsConsole;
consolePanel.clearConsole();
}
});
actionGroup.add(new DumbAwareAction(CodeGPTBundle.get("llama.ui.action.scrollToEnd"), CodeGPTBundle.get("llama.ui.action.scrollToEnd.description"),
AllIcons.RunConfigurations.Scroll_down) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
var consolePanel = isServerLogs ? serverLogsConsole : buildLogsConsole;
consolePanel.setCaretPosition(consolePanel.getDocument().getLength());
}
});
var toolbar = ActionManager.getInstance().createActionToolbar("LlamaLogs", actionGroup, true);
toolbar.setTargetComponent(this);
return toolbar.getComponent();
}
private JPanel createStatusBar() {
var statusBar = new JPanel(new BorderLayout());
statusBar.setBorder(JBUI.Borders.compound(
JBUI.Borders.customLine(JBUI.CurrentTheme.ToolWindow.borderColor(), 1, 0, 0, 0),
JBUI.Borders.empty(4)
));
statusBar.add(serverStatusPanel, BorderLayout.WEST);
return statusBar;
}
private void loadExistingLogs() {
ApplicationManager.getApplication().executeOnPooledThread(() -> {
var logsManager = ApplicationManager.getApplication().getService(ServerLogsManager.class);
var logs = logsManager.getSessionLogs(logsManager.getCurrentSession().getId());
SwingUtilities.invokeLater(() -> {
for (var log : logs) {
boolean isError = log.getMessage().toLowerCase().contains("error") ||
log.getMessage().toLowerCase().contains("exception") ||
log.getMessage().toLowerCase().contains("failed");
serverLogsConsole.appendText(log.getMessage(), isError);
}
});
});
}
private void updateServerStatus() {
SwingUtilities.invokeLater(() -> {
if (serverAgent.isServerRunning()) {
serverStatusLabel.setText(CodeGPTBundle.get("llama.ui.status.running"));
serverStatusLabel.setIcon(AllIcons.General.InspectionsOK);
serverStatusLabel.setForeground(JBColor.GREEN);
serverStatusSpinner.setVisible(false);
setTabState(SERVER_LOGS_TAB, true, SERVER_LOGS_DISABLED_TOOLTIP);
setTabState(BUILD_OUTPUT_TAB, false, BUILD_OUTPUT_DISABLED_TOOLTIP);
} else if (serverAgent.isBuildInProgress()) {
serverStatusLabel.setText(CodeGPTBundle.get("llama.ui.status.building"));
serverStatusLabel.setIcon(null);
serverStatusLabel.setForeground(JBColor.BLUE);
serverStatusSpinner.setVisible(true);
setTabState(SERVER_LOGS_TAB, false, SERVER_LOGS_DISABLED_TOOLTIP);
setTabState(BUILD_OUTPUT_TAB, true, BUILD_OUTPUT_DISABLED_TOOLTIP);
} else {
serverStatusLabel.setText(CodeGPTBundle.get("llama.ui.status.stopped"));
serverStatusLabel.setIcon(AllIcons.General.InspectionsEye);
serverStatusLabel.setForeground(JBColor.GRAY);
serverStatusSpinner.setVisible(false);
setTabState(SERVER_LOGS_TAB, false, SERVER_LOGS_DISABLED_TOOLTIP);
setTabState(BUILD_OUTPUT_TAB, false, BUILD_OUTPUT_DISABLED_TOOLTIP);
}
});
}
public void refreshServerStatus() {
updateServerStatus();
}
public void updateServerStatusWithPhase(String phase) {
SwingUtilities.invokeLater(() -> {
serverStatusLabel.setText(CodeGPTBundle.get("llama.ui.status.prefix").replace("{0}", phase));
serverStatusLabel.setIcon(null);
serverStatusLabel.setForeground(JBColor.BLUE);
serverStatusSpinner.setVisible(true);
});
}
public void logToConsole(String message, boolean isError, boolean isBuildLog) {
var consolePanel = isBuildLog ? buildLogsConsole : serverLogsConsole;
if (consolePanel != null) {
consolePanel.appendText(message, isError);
}
}
public LlamaSettingsState getCurrentState() {
var state = new LlamaSettingsState();
state.setTopK(llamaRequestPreferencesForm.getTopK());
state.setTopP(llamaRequestPreferencesForm.getTopP());
state.setMinP(llamaRequestPreferencesForm.getMinP());
state.setRepeatPenalty(llamaRequestPreferencesForm.getRepeatPenalty());
state.setRemoteModelPromptTemplate(llamaServerPreferencesForm.getPromptTemplate());
state.setRemoteModelInfillPromptTemplate(llamaServerPreferencesForm.getInfillPromptTemplate());
state.setRunLocalServer(llamaServerPreferencesForm.isRunLocalServer());
state.setBaseHost(llamaServerPreferencesForm.getBaseHost());
state.setServerPort(llamaServerPreferencesForm.getServerPort());
state.setContextSize(llamaServerPreferencesForm.getContextSize());
state.setThreads(llamaServerPreferencesForm.getThreads());
state.setAdditionalParameters(llamaServerPreferencesForm.getAdditionalParameters());
state.setAdditionalBuildParameters(llamaServerPreferencesForm.getAdditionalBuildParameters());
state.setServerPort(serverPreferencesForm.getServerPort());
state.setContextSize(serverPreferencesForm.getContextSize());
state.setThreads(serverPreferencesForm.getThreads());
state.setAdditionalParameters(serverPreferencesForm.getAdditionalParameters());
state.setAdditionalBuildParameters(serverPreferencesForm.getAdditionalBuildParameters());
state.setAdditionalEnvironmentVariables(
llamaServerPreferencesForm.getAdditionalEnvironmentVariables());
serverPreferencesForm.getAdditionalEnvironmentVariables());
var modelPreferencesForm = llamaServerPreferencesForm.getLlamaModelPreferencesForm();
state.setTopK(settingsState.getTopK());
state.setTopP(settingsState.getTopP());
state.setMinP(settingsState.getMinP());
state.setRepeatPenalty(settingsState.getRepeatPenalty());
var modelPreferencesForm = serverPreferencesForm.getLlamaModelPreferencesForm();
state.setCustomLlamaModelPath(modelPreferencesForm.getCustomLlamaModelPath());
state.setHuggingFaceModel(modelPreferencesForm.getSelectedModel());
state.setUseCustomModel(modelPreferencesForm.isUseCustomLlamaModel());
state.setHuggingFaceModel(modelPreferencesForm.getSelectedModel());
state.setLocalModelPromptTemplate(modelPreferencesForm.getPromptTemplate());
state.setLocalModelInfillPromptTemplate(modelPreferencesForm.getInfillPromptTemplate());
state.setCodeCompletionsEnabled(codeCompletionConfigurationForm.isCodeCompletionsEnabled());
state.setCodeCompletionsEnabled(settingsState.isCodeCompletionsEnabled());
return state;
}
public void resetForm() {
var state = LlamaSettings.getCurrentState();
llamaServerPreferencesForm.resetForm(state);
llamaRequestPreferencesForm.resetForm(state);
codeCompletionConfigurationForm.setCodeCompletionsEnabled(state.isCodeCompletionsEnabled());
serverPreferencesForm.resetForm(settingsState);
}
public LlamaServerPreferencesForm getLlamaServerPreferencesForm() {
return llamaServerPreferencesForm;
public void resetForm(LlamaSettingsState newState) {
serverPreferencesForm.resetForm(newState);
}
private void init() {
setLayout(new BorderLayout());
add(FormBuilder.createFormBuilder()
.addComponent(new TitledSeparator("Code Completions"))
.addComponent(withEmptyLeftBorder(codeCompletionConfigurationForm.getForm()))
.addComponent(new TitledSeparator(
CodeGPTBundle.get("settingsConfigurable.service.llama.serverPreferences.title")))
.addComponent(llamaServerPreferencesForm.getForm())
.addComponent(new TitledSeparator("Request Preferences"))
.addComponent(withEmptyLeftBorder(llamaRequestPreferencesForm.getForm()))
.addComponentFillVertically(new JPanel(), 0)
.getPanel());
private void setTabState(int tabIndex, boolean enabled, String disabledTooltip) {
tabbedPane.setEnabledAt(tabIndex, enabled);
tabbedPane.setToolTipTextAt(tabIndex, enabled ? null : disabledTooltip);
}
}
}

View file

@ -1,28 +0,0 @@
package ee.carlrobert.codegpt.settings.service.llama.form;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.AsyncProcessIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class ServerProgressPanel extends JPanel {
private final JBLabel label = new JBLabel();
private final AsyncProcessIcon loadingSpinner = new AsyncProcessIcon("sign_in_spinner");
public void displayText(String text) {
label.setText(text);
removeAll();
add(loadingSpinner);
add(label);
revalidate();
repaint();
}
public void displayComponent(JComponent component) {
removeAll();
add(component);
revalidate();
repaint();
}
}

View file

@ -286,10 +286,6 @@ public class ModelComboBoxAction extends ComboBoxAction {
}
private String getLlamaCppPresentationText() {
var llamaSettingState = LlamaSettings.getCurrentState();
if (!llamaSettingState.isRunLocalServer()) {
return format("Remote %s", llamaSettingState.getRemoteModelPromptTemplate());
}
return getSelectedHuggingFace();
}