mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-19 16:28:46 +00:00
feat: add server and build logs for llama.cpp
This commit is contained in:
parent
768d410737
commit
e11477ded3
30 changed files with 2231 additions and 1086 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,9 @@ import ee.carlrobert.codegpt.completions.llama.LlamaServerStartupParams
|
|||
import ee.carlrobert.codegpt.settings.GeneralSettings
|
||||
import ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings.*
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.ServerProgressPanel
|
||||
import ee.carlrobert.codegpt.completions.llama.logging.NoOpLoggingStrategy
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil.showNotification
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil.stickyNotification
|
||||
import java.util.function.Consumer
|
||||
|
||||
private const val STARTING = "settingsConfigurable.service.llama.progress.startingServer"
|
||||
private const val RUNNING = "settingsConfigurable.service.llama.progress.serverRunning"
|
||||
|
|
@ -62,10 +60,10 @@ abstract class LlamaServerToggleActions(
|
|||
}
|
||||
|
||||
private fun start(serverName: String, llamaServerAgent: LlamaServerAgent) {
|
||||
notification = stickyNotification(formatMsg(STARTING, serverName),
|
||||
notification = stickyNotification(
|
||||
formatMsg(STARTING, serverName),
|
||||
createSimpleExpiring(CodeGPTBundle.get(STOP)) { stop(serverName, llamaServerAgent) })
|
||||
val serverProgressPanel = ServerProgressPanel()
|
||||
llamaServerAgent.setActiveServerProgressPanel(serverProgressPanel)
|
||||
|
||||
val settings = LlamaSettings.getInstance().state
|
||||
llamaServerAgent.startAgent(
|
||||
LlamaServerStartupParams(
|
||||
|
|
@ -73,20 +71,18 @@ abstract class LlamaServerToggleActions(
|
|||
settings.contextSize,
|
||||
settings.threads,
|
||||
settings.serverPort,
|
||||
getAdditionalParametersList(settings.additionalParameters),
|
||||
getAdditionalParametersList(settings.additionalBuildParameters),
|
||||
getAdditionalEnvironmentVariablesMap(settings.additionalEnvironmentVariables)
|
||||
LlamaSettings.getAdditionalParametersList(settings.additionalParameters),
|
||||
LlamaSettings.getAdditionalParametersList(settings.additionalBuildParameters),
|
||||
LlamaSettings.getAdditionalEnvironmentVariablesMap(settings.additionalEnvironmentVariables)
|
||||
),
|
||||
serverProgressPanel,
|
||||
NoOpLoggingStrategy,
|
||||
{
|
||||
notification?.expire()
|
||||
notification = notification(RUNNING, false, serverName, llamaServerAgent)
|
||||
},
|
||||
{
|
||||
Consumer<ServerProgressPanel> { _: ServerProgressPanel ->
|
||||
notification?.expire()
|
||||
notification = notification(STOPPED, true, serverName, llamaServerAgent)
|
||||
}
|
||||
notification?.expire()
|
||||
notification = notification(STOPPED, true, serverName, llamaServerAgent)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -98,13 +94,12 @@ abstract class LlamaServerToggleActions(
|
|||
}
|
||||
|
||||
private fun notification(id: String, nextStart: Boolean, serverName: String, llamaServerAgent: LlamaServerAgent) =
|
||||
showNotification(formatMsg(id, serverName),
|
||||
showNotification(
|
||||
formatMsg(id, serverName),
|
||||
createSimpleExpiring(CodeGPTBundle.get(if (nextStart) START else STOP)) {
|
||||
if (nextStart) start(serverName, llamaServerAgent) else stop(serverName, llamaServerAgent)
|
||||
})
|
||||
|
||||
// "Starting server..." -> "Starting server: CodeLlama 7B 4-bit ..."
|
||||
// "Stopped server" -> "Stopped server: CodeLlama 7B 4-bit"
|
||||
private fun formatMsg(id: String, serverName: String): String {
|
||||
val msg = CodeGPTBundle.get(id)
|
||||
val points = msg.endsWith("...")
|
||||
|
|
@ -112,7 +107,8 @@ abstract class LlamaServerToggleActions(
|
|||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val llamaRunnable = isRunnable(LlamaSettings.getInstance().state.huggingFaceModel)
|
||||
val llamaRunnable =
|
||||
LlamaSettings.isRunnable(LlamaSettings.getInstance().state.huggingFaceModel)
|
||||
val serverRunning = llamaRunnable && service<LlamaServerAgent>().isServerRunning
|
||||
val toggle = llamaRunnable && serverRunning != startServer
|
||||
e.presentation.isVisible = toggle
|
||||
|
|
|
|||
|
|
@ -144,9 +144,6 @@ object CodeCompletionRequestFactory {
|
|||
}
|
||||
|
||||
private fun getLlamaInfillPromptTemplate(settings: LlamaSettingsState): InfillPromptTemplate {
|
||||
if (!settings.isRunLocalServer) {
|
||||
return settings.remoteModelInfillPromptTemplate
|
||||
}
|
||||
if (settings.isUseCustomModel) {
|
||||
return settings.localModelInfillPromptTemplate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,14 +50,10 @@ class LlamaRequestFactory : BaseRequestFactory() {
|
|||
|
||||
private fun getPromptTemplate(): PromptTemplate {
|
||||
val settings = service<LlamaSettings>().state
|
||||
return if (settings.isRunLocalServer) {
|
||||
if (settings.isUseCustomModel)
|
||||
settings.localModelPromptTemplate
|
||||
else
|
||||
LlamaModel.findByHuggingFaceModel(settings.huggingFaceModel).promptTemplate
|
||||
} else {
|
||||
settings.remoteModelPromptTemplate
|
||||
}
|
||||
return if (settings.isUseCustomModel)
|
||||
settings.localModelPromptTemplate
|
||||
else
|
||||
LlamaModel.findByHuggingFaceModel(settings.huggingFaceModel).promptTemplate
|
||||
}
|
||||
|
||||
private fun buildLlamaRequest(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,212 @@
|
|||
package ee.carlrobert.codegpt.completions.llama
|
||||
|
||||
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.ProcessOutputType
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.util.Key
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle
|
||||
import ee.carlrobert.codegpt.CodeGPTPlugin
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.BUILD_CONFIGURATION
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.BUILD_DIRECTORY
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.BUILD_PARALLEL_JOBS
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.PROGRESS_CMAKE_BUILD
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.PROGRESS_CMAKE_SETUP
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
class BuildPhaseManager(
|
||||
private val infoLogger: (String) -> Unit,
|
||||
private val errorLogger: (String) -> Unit,
|
||||
private val phaseUpdater: (String) -> Unit,
|
||||
private val progressStopper: () -> Unit
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val logger = thisLogger()
|
||||
|
||||
private fun getAbsoluteBuildPath(): String {
|
||||
return Paths.get(CodeGPTPlugin.getLlamaSourcePath(), BUILD_DIRECTORY).toAbsolutePath()
|
||||
.toString()
|
||||
}
|
||||
|
||||
private fun isCMakeCacheConflict(buildPath: String): Boolean {
|
||||
val cacheFile = File(buildPath, "CMakeCache.txt")
|
||||
if (!cacheFile.exists()) return false
|
||||
|
||||
try {
|
||||
val cacheContent = cacheFile.readText()
|
||||
val currentSourcePath = CodeGPTPlugin.getLlamaSourcePath()
|
||||
|
||||
val homeDirectoryRegex = """CMAKE_HOME_DIRECTORY:INTERNAL=(.+)""".toRegex()
|
||||
val match = homeDirectoryRegex.find(cacheContent)
|
||||
|
||||
return match?.groupValues?.get(1)?.let { cachedPath ->
|
||||
!Paths.get(cachedPath).toAbsolutePath()
|
||||
.equals(Paths.get(currentSourcePath).toAbsolutePath())
|
||||
} == true
|
||||
} catch (e: Exception) {
|
||||
logger.warn("Failed to read CMake cache file", e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanupCMakeCache(buildPath: String) {
|
||||
try {
|
||||
val buildDir = File(buildPath)
|
||||
if (buildDir.exists()) {
|
||||
logger.info("Cleaning up CMake cache due to path mismatch: $buildPath")
|
||||
Files.walk(buildDir.toPath())
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.map { it.toFile() }
|
||||
.forEach { it.delete() }
|
||||
buildDir.mkdirs()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.warn("Failed to cleanup CMake cache", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
fun executeCMakeSetup(
|
||||
params: LlamaServerStartupParams,
|
||||
indicator: ProgressIndicator,
|
||||
onSuccess: () -> Unit,
|
||||
onError: (String) -> Unit
|
||||
): OSProcessHandler {
|
||||
|
||||
indicator.text = CodeGPTBundle.get("llama.build.cmake.setup")
|
||||
indicator.fraction = PROGRESS_CMAKE_SETUP
|
||||
|
||||
phaseUpdater(CodeGPTBundle.get("llama.build.cmake.setup"))
|
||||
infoLogger("=== " + CodeGPTBundle.get("llama.build.startingBuild") + " ===")
|
||||
infoLogger(CodeGPTBundle.get("llama.build.phase.setup"))
|
||||
infoLogger(CodeGPTBundle.get("llamaServerAgent.buildingProject.description"))
|
||||
|
||||
val buildPath = getAbsoluteBuildPath()
|
||||
if (isCMakeCacheConflict(buildPath)) {
|
||||
infoLogger(CodeGPTBundle.get("llama.build.cache.cleanup"))
|
||||
cleanupCMakeCache(buildPath)
|
||||
}
|
||||
|
||||
val handler = OSProcessHandler(getCMakeSetupCommandLine(params))
|
||||
handler.addProcessListener(object : ProcessAdapter() {
|
||||
private val errorLines = CopyOnWriteArrayList<String>()
|
||||
|
||||
override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {
|
||||
if (ProcessOutputType.isStderr(outputType)) {
|
||||
errorLines.add(event.text)
|
||||
errorLogger(event.text.trim())
|
||||
return
|
||||
}
|
||||
logger.info(event.text)
|
||||
infoLogger(event.text.trim())
|
||||
}
|
||||
|
||||
override fun processTerminated(event: ProcessEvent) {
|
||||
val exitCode = event.exitCode
|
||||
val exitMessage = "CMake setup exited with code $exitCode"
|
||||
logger.info(exitMessage)
|
||||
|
||||
if (exitCode != 0) {
|
||||
errorLogger(exitMessage)
|
||||
phaseUpdater(CodeGPTBundle.get("llama.build.phase.setupFailed"))
|
||||
progressStopper()
|
||||
onError(errorLines.joinToString(","))
|
||||
} else {
|
||||
infoLogger(exitMessage)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
fun executeCMakeBuild(
|
||||
params: LlamaServerStartupParams,
|
||||
indicator: ProgressIndicator,
|
||||
onSuccess: () -> Unit,
|
||||
onError: (String) -> Unit
|
||||
): OSProcessHandler {
|
||||
|
||||
indicator.text = CodeGPTBundle.get("llama.build.cmake.build")
|
||||
indicator.fraction = PROGRESS_CMAKE_BUILD
|
||||
|
||||
phaseUpdater(CodeGPTBundle.get("llama.build.cmake.build"))
|
||||
infoLogger(CodeGPTBundle.get("llama.build.phase.build"))
|
||||
|
||||
val handler = OSProcessHandler(getCMakeBuildCommandLine(params))
|
||||
handler.addProcessListener(object : ProcessAdapter() {
|
||||
private val errorLines = CopyOnWriteArrayList<String>()
|
||||
|
||||
override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {
|
||||
if (ProcessOutputType.isStderr(outputType)) {
|
||||
errorLines.add(event.text)
|
||||
errorLogger(event.text.trim())
|
||||
return
|
||||
}
|
||||
logger.info(event.text)
|
||||
infoLogger(event.text.trim())
|
||||
}
|
||||
|
||||
override fun processTerminated(event: ProcessEvent) {
|
||||
val exitCode = event.exitCode
|
||||
val exitMessage = "Server build exited with code $exitCode"
|
||||
logger.info(exitMessage)
|
||||
|
||||
if (exitCode != 0) {
|
||||
errorLogger(exitMessage)
|
||||
phaseUpdater(CodeGPTBundle.get("llama.build.phase.buildFailed"))
|
||||
progressStopper()
|
||||
onError(errorLines.joinToString(","))
|
||||
} else {
|
||||
infoLogger(exitMessage)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
private fun getCMakeSetupCommandLine(params: LlamaServerStartupParams): GeneralCommandLine {
|
||||
val absoluteBuildPath = getAbsoluteBuildPath()
|
||||
return GeneralCommandLine().apply {
|
||||
charset = StandardCharsets.UTF_8
|
||||
exePath = "cmake"
|
||||
withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath())
|
||||
addParameters("-B", absoluteBuildPath)
|
||||
withEnvironment(params.additionalEnvironmentVariables())
|
||||
isRedirectErrorStream = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCMakeBuildCommandLine(params: LlamaServerStartupParams): GeneralCommandLine {
|
||||
val absoluteBuildPath = getAbsoluteBuildPath()
|
||||
return GeneralCommandLine().apply {
|
||||
charset = StandardCharsets.UTF_8
|
||||
exePath = "cmake"
|
||||
withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath())
|
||||
addParameters(
|
||||
"--build",
|
||||
absoluteBuildPath,
|
||||
"--config",
|
||||
BUILD_CONFIGURATION,
|
||||
"-j",
|
||||
BUILD_PARALLEL_JOBS.toString()
|
||||
)
|
||||
withEnvironment(params.additionalEnvironmentVariables())
|
||||
isRedirectErrorStream = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package ee.carlrobert.codegpt.completions.llama
|
||||
|
||||
object LlamaConstants {
|
||||
const val PROGRESS_CMAKE_SETUP = 0.0
|
||||
const val PROGRESS_CMAKE_BUILD = 0.33
|
||||
const val PROGRESS_SERVER_START = 0.66
|
||||
|
||||
const val BUILD_PARALLEL_JOBS = 4
|
||||
const val BUILD_CONFIGURATION = "Release"
|
||||
const val BUILD_DIRECTORY = "build"
|
||||
|
||||
const val SERVER_EXECUTABLE_PATH = "./build/bin/llama-server"
|
||||
const val SERVER_LISTENING_MESSAGE = "server is listening"
|
||||
|
||||
const val MAX_LOG_ENTRIES = 10000
|
||||
const val MAX_LOG_SESSIONS = 5
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package ee.carlrobert.codegpt.completions.llama
|
||||
|
||||
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.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.Key
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle
|
||||
import ee.carlrobert.codegpt.CodeGPTPlugin
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.SERVER_EXECUTABLE_PATH
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.SERVER_LISTENING_MESSAGE
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
|
||||
class LlamaProcessManager(
|
||||
private val infoLogger: (String) -> Unit,
|
||||
private val errorLogger: (String) -> Unit
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(LlamaProcessManager::class.java)
|
||||
}
|
||||
|
||||
private var serverProcessHandler: OSProcessHandler? = null
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
fun startServer(
|
||||
params: LlamaServerStartupParams,
|
||||
onSuccess: () -> Unit,
|
||||
onError: (String) -> Unit
|
||||
) {
|
||||
LOG.info("Booting up llama server")
|
||||
infoLogger("Phase 3: Starting Server")
|
||||
infoLogger("=== Starting Llama Server ===")
|
||||
infoLogger(CodeGPTBundle.get("llamaServerAgent.serverBootup.description"))
|
||||
|
||||
serverProcessHandler = OSProcessHandler.Silent(getServerCommandLine(params)).apply {
|
||||
addProcessListener(createServerProcessListener(
|
||||
params.port(),
|
||||
onSuccess,
|
||||
onError
|
||||
))
|
||||
startNotify()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopServer() {
|
||||
serverProcessHandler?.let {
|
||||
if (!it.isProcessTerminated) {
|
||||
it.destroyProcess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isServerRunning(): Boolean {
|
||||
return serverProcessHandler?.let {
|
||||
it.isStartNotified && !it.isProcessTerminated
|
||||
} == true
|
||||
}
|
||||
|
||||
private fun createServerProcessListener(
|
||||
port: Int,
|
||||
onSuccess: () -> Unit,
|
||||
onError: (String) -> Unit
|
||||
): ProcessListener {
|
||||
return object : ProcessAdapter() {
|
||||
private val errorLines = CopyOnWriteArrayList<String>()
|
||||
|
||||
override fun processTerminated(event: ProcessEvent) {
|
||||
val message = "Server stopped with code ${event.exitCode}"
|
||||
LOG.info(message)
|
||||
|
||||
if (event.exitCode != 0) {
|
||||
errorLogger(message)
|
||||
onError(errorLines.joinToString(","))
|
||||
} else {
|
||||
infoLogger(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {
|
||||
LOG.debug(event.text)
|
||||
infoLogger(event.text.trim())
|
||||
|
||||
if (event.text.contains(SERVER_LISTENING_MESSAGE)) {
|
||||
val successMessage = "Server up and running!"
|
||||
LOG.info(successMessage)
|
||||
infoLogger(successMessage)
|
||||
|
||||
LlamaSettings.getCurrentState().serverPort = port
|
||||
|
||||
runInEdt { onSuccess() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getServerCommandLine(params: LlamaServerStartupParams): GeneralCommandLine {
|
||||
return GeneralCommandLine().apply {
|
||||
charset = StandardCharsets.UTF_8
|
||||
exePath = SERVER_EXECUTABLE_PATH
|
||||
withWorkDirectory(CodeGPTPlugin.getLlamaSourcePath())
|
||||
addParameters(
|
||||
"-m", params.modelPath(),
|
||||
"-c", params.contextLength().toString(),
|
||||
"--port", params.port().toString(),
|
||||
"-t", params.threads().toString()
|
||||
)
|
||||
addParameters(params.additionalRunParameters())
|
||||
withEnvironment(params.additionalEnvironmentVariables())
|
||||
isRedirectErrorStream = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
package ee.carlrobert.codegpt.completions.llama
|
||||
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.process.OSProcessHandler
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.util.application
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.PROGRESS_SERVER_START
|
||||
import ee.carlrobert.codegpt.completions.llama.logging.NoOpLoggingStrategy
|
||||
import ee.carlrobert.codegpt.completions.llama.logging.ServerLoggingStrategy
|
||||
import ee.carlrobert.codegpt.services.llama.ServerLogsManager
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm
|
||||
|
||||
@Service
|
||||
class LlamaServerAgent : Disposable {
|
||||
|
||||
companion object {
|
||||
private val logger = thisLogger()
|
||||
}
|
||||
|
||||
private val buildPhaseManager: BuildPhaseManager = BuildPhaseManager(
|
||||
infoLogger = { message -> logToConsole(message, false, true) },
|
||||
errorLogger = { message -> logToConsole(message, true, true) },
|
||||
phaseUpdater = { phase -> updatePhase(phase) },
|
||||
progressStopper = { stopProgress() }
|
||||
)
|
||||
|
||||
private val processManager: LlamaProcessManager = LlamaProcessManager(
|
||||
infoLogger = { message -> logToConsole(message, false, false) },
|
||||
errorLogger = { message -> logToConsole(message, true, false) }
|
||||
)
|
||||
|
||||
@Volatile
|
||||
private var stoppedByUser: Boolean = false
|
||||
|
||||
@Volatile
|
||||
private var buildInProgress: Boolean = false
|
||||
|
||||
@Volatile
|
||||
private var currentProgressIndicator: ProgressIndicator? = null
|
||||
|
||||
@Volatile
|
||||
private var setupProcessHandler: OSProcessHandler? = null
|
||||
|
||||
@Volatile
|
||||
private var buildProcessHandler: OSProcessHandler? = null
|
||||
|
||||
private var loggingStrategy: ServerLoggingStrategy = NoOpLoggingStrategy
|
||||
private var settingsForm: LlamaSettingsForm? = null
|
||||
|
||||
fun startAgent(
|
||||
params: LlamaServerStartupParams,
|
||||
loggingStrategy: ServerLoggingStrategy = NoOpLoggingStrategy,
|
||||
onSuccess: Runnable,
|
||||
onServerStopped: Runnable
|
||||
) {
|
||||
this.loggingStrategy = loggingStrategy
|
||||
|
||||
application.service<ServerLogsManager>().startNewSession()
|
||||
|
||||
ProgressManager.getInstance()
|
||||
.run(object : Task.Backgroundable(null, CodeGPTBundle.get("llama.build.startingBuild"), true) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
currentProgressIndicator = indicator
|
||||
indicator.isIndeterminate = false
|
||||
buildServer(params, indicator, onSuccess, onServerStopped)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildServer(
|
||||
params: LlamaServerStartupParams,
|
||||
indicator: ProgressIndicator,
|
||||
onSuccess: Runnable,
|
||||
onServerStopped: Runnable
|
||||
) {
|
||||
try {
|
||||
stoppedByUser = false
|
||||
buildInProgress = true
|
||||
|
||||
loggingStrategy.startProgress()
|
||||
|
||||
if (indicator.isCanceled) {
|
||||
stoppedByUser = true
|
||||
return
|
||||
}
|
||||
|
||||
setupProcessHandler = buildPhaseManager.executeCMakeSetup(params, indicator, {
|
||||
if (stoppedByUser) {
|
||||
buildInProgress = false
|
||||
clearProcessHandlers()
|
||||
logToConsole(CodeGPTBundle.get("llama.server.buildStopped"), false, true)
|
||||
onServerStopped.run()
|
||||
return@executeCMakeSetup
|
||||
}
|
||||
|
||||
if (indicator.isCanceled) {
|
||||
stoppedByUser = true
|
||||
return@executeCMakeSetup
|
||||
}
|
||||
|
||||
try {
|
||||
buildProcessHandler = buildPhaseManager.executeCMakeBuild(params, indicator, {
|
||||
if (stoppedByUser) {
|
||||
buildInProgress = false
|
||||
logToConsole(CodeGPTBundle.get("llama.server.buildStopped"), false, true)
|
||||
onServerStopped.run()
|
||||
return@executeCMakeBuild
|
||||
}
|
||||
|
||||
indicator.text = CodeGPTBundle.get("llama.server.starting")
|
||||
indicator.fraction = PROGRESS_SERVER_START
|
||||
|
||||
loggingStrategy.setPhase(CodeGPTBundle.get("llama.server.starting"))
|
||||
|
||||
if (indicator.isCanceled) {
|
||||
stoppedByUser = true
|
||||
return@executeCMakeBuild
|
||||
}
|
||||
|
||||
try {
|
||||
processManager.startServer(params, {
|
||||
loggingStrategy.apply {
|
||||
setPhase(CodeGPTBundle.get("llama.server.running"))
|
||||
indicator.text = CodeGPTBundle.get("llama.server.running")
|
||||
indicator.fraction = 1.0
|
||||
stopProgress()
|
||||
}
|
||||
|
||||
settingsForm?.refreshServerStatus()
|
||||
buildInProgress = false
|
||||
clearProcessHandlers()
|
||||
onSuccess.run()
|
||||
}) { errorText ->
|
||||
showServerError(errorText, onServerStopped)
|
||||
}
|
||||
} catch (e: ExecutionException) {
|
||||
showServerError(e.message ?: "Unknown error", onServerStopped)
|
||||
}
|
||||
}) { errorText ->
|
||||
showServerError(errorText, onServerStopped)
|
||||
}
|
||||
|
||||
buildProcessHandler?.startNotify()
|
||||
} catch (e: ExecutionException) {
|
||||
showServerError(e.message ?: "Unknown error", onServerStopped)
|
||||
}
|
||||
}) { errorText ->
|
||||
showServerError(errorText, onServerStopped)
|
||||
}
|
||||
|
||||
setupProcessHandler?.startNotify()
|
||||
} catch (e: ExecutionException) {
|
||||
showServerError(e.message ?: "Unknown error", onServerStopped)
|
||||
}
|
||||
}
|
||||
|
||||
fun stopAgent() {
|
||||
stoppedByUser = true
|
||||
buildInProgress = false
|
||||
|
||||
currentProgressIndicator?.cancel()
|
||||
|
||||
setupProcessHandler?.let { handler ->
|
||||
if (!handler.isProcessTerminated) {
|
||||
handler.destroyProcess()
|
||||
logToConsole(CodeGPTBundle.get("llama.server.stopping.cmake"), false, true)
|
||||
}
|
||||
}
|
||||
|
||||
buildProcessHandler?.let { handler ->
|
||||
if (!handler.isProcessTerminated) {
|
||||
handler.destroyProcess()
|
||||
logToConsole(CodeGPTBundle.get("llama.server.stopping.build"), false, true)
|
||||
}
|
||||
}
|
||||
|
||||
processManager.stopServer()
|
||||
|
||||
currentProgressIndicator = null
|
||||
setupProcessHandler = null
|
||||
buildProcessHandler = null
|
||||
}
|
||||
|
||||
val isServerRunning: Boolean
|
||||
get() = processManager.isServerRunning()
|
||||
|
||||
val isBuildInProgress: Boolean
|
||||
get() = buildInProgress
|
||||
|
||||
private fun showServerError(errorText: String, onServerStopped: Runnable) {
|
||||
buildInProgress = false
|
||||
clearProcessHandlers()
|
||||
|
||||
loggingStrategy.apply {
|
||||
setPhase(CodeGPTBundle.get("llama.server.startupFailed"))
|
||||
stopProgress()
|
||||
}
|
||||
|
||||
logToConsole(CodeGPTBundle.get("llama.error.server.startupWithDetails", errorText), true, false)
|
||||
onServerStopped.run()
|
||||
|
||||
val enhancedErrorMessage = CodeGPTBundle.get("llama.error.server.startup", errorText)
|
||||
|
||||
logger.info(enhancedErrorMessage)
|
||||
logToConsole(enhancedErrorMessage, true, false)
|
||||
}
|
||||
|
||||
private fun clearProcessHandlers() {
|
||||
currentProgressIndicator = null
|
||||
setupProcessHandler = null
|
||||
buildProcessHandler = null
|
||||
}
|
||||
|
||||
fun setSettingsForm(settingsForm: LlamaSettingsForm?) {
|
||||
this.settingsForm = settingsForm
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun logToConsole(message: String, isError: Boolean, isBuildLog: Boolean = false) {
|
||||
application.service<ServerLogsManager>().log(message, isError)
|
||||
loggingStrategy.logMessage(message, isError, isBuildLog)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
try {
|
||||
stopAgent()
|
||||
} catch (e: Exception) {
|
||||
logger.error("Error during disposal", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePhase(phase: String) {
|
||||
loggingStrategy.setPhase(phase)
|
||||
}
|
||||
|
||||
private fun stopProgress() {
|
||||
loggingStrategy.stopProgress()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package ee.carlrobert.codegpt.completions.llama
|
||||
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.Color
|
||||
import java.awt.Font
|
||||
import java.awt.RenderingHints
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
import javax.swing.JTextPane
|
||||
import javax.swing.text.BadLocationException
|
||||
import javax.swing.text.SimpleAttributeSet
|
||||
import javax.swing.text.StyleConstants
|
||||
|
||||
class SimpleConsolePanel : JTextPane() {
|
||||
|
||||
private val lineBuffer = ConcurrentLinkedDeque<String>()
|
||||
private val backgroundColor = JBColor.namedColor("Console.background", Color(43, 43, 43))
|
||||
private val normalTextColor = JBColor.namedColor("Console.foreground", Color(204, 204, 204))
|
||||
private val errorTextColor = JBColor.namedColor("Console.errorForeground", Color(255, 102, 102))
|
||||
private val timestampColor = JBColor.namedColor("Console.grayForeground", Color(153, 153, 153))
|
||||
private val normalAttributes = SimpleAttributeSet()
|
||||
private val errorAttributes = SimpleAttributeSet()
|
||||
private val timestampAttributes = SimpleAttributeSet()
|
||||
|
||||
companion object {
|
||||
private const val MAX_LINES = 1000
|
||||
private val TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss")
|
||||
}
|
||||
|
||||
init {
|
||||
setupConsoleAppearance()
|
||||
setupStyles()
|
||||
}
|
||||
|
||||
private fun setupConsoleAppearance() {
|
||||
isEditable = false
|
||||
background = backgroundColor
|
||||
foreground = normalTextColor
|
||||
font = JBUI.Fonts.create(Font.MONOSPACED, JBUI.scaleFontSize(12.0f).toInt())
|
||||
putClientProperty(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON
|
||||
)
|
||||
putClientProperty(
|
||||
RenderingHints.KEY_FRACTIONALMETRICS,
|
||||
RenderingHints.VALUE_FRACTIONALMETRICS_ON
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupStyles() {
|
||||
val baseFont = JBUI.Fonts.create(Font.MONOSPACED, JBUI.scaleFontSize(12.0f).toInt())
|
||||
val smallFont = JBUI.Fonts.create(Font.MONOSPACED, JBUI.scaleFontSize(11.0f).toInt())
|
||||
StyleConstants.setForeground(normalAttributes, normalTextColor)
|
||||
StyleConstants.setFontFamily(normalAttributes, baseFont.family)
|
||||
StyleConstants.setFontSize(normalAttributes, baseFont.size)
|
||||
StyleConstants.setForeground(errorAttributes, errorTextColor)
|
||||
StyleConstants.setFontFamily(errorAttributes, baseFont.family)
|
||||
StyleConstants.setFontSize(errorAttributes, baseFont.size)
|
||||
StyleConstants.setBold(errorAttributes, true)
|
||||
StyleConstants.setForeground(timestampAttributes, timestampColor)
|
||||
StyleConstants.setFontFamily(timestampAttributes, smallFont.family)
|
||||
StyleConstants.setFontSize(timestampAttributes, smallFont.size)
|
||||
}
|
||||
|
||||
fun appendText(message: String, isError: Boolean = false) {
|
||||
try {
|
||||
val timestamp = LocalDateTime.now().format(TIMESTAMP_FORMAT)
|
||||
val fullMessage = "[$timestamp] $message"
|
||||
lineBuffer.add(fullMessage)
|
||||
while (lineBuffer.size > MAX_LINES) {
|
||||
lineBuffer.pollFirst()
|
||||
removeFirstLine()
|
||||
}
|
||||
|
||||
val doc = styledDocument
|
||||
val startOffset = doc.length
|
||||
doc.insertString(startOffset, "[$timestamp] ", timestampAttributes)
|
||||
val messageStyle = if (isError) errorAttributes else normalAttributes
|
||||
doc.insertString(doc.length, "$message\n", messageStyle)
|
||||
caretPosition = doc.length
|
||||
} catch (e: BadLocationException) {
|
||||
val timestamp = LocalDateTime.now().format(TIMESTAMP_FORMAT)
|
||||
text = "$text[$timestamp] $message\n"
|
||||
caretPosition = text.length
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeFirstLine() {
|
||||
try {
|
||||
val doc = styledDocument
|
||||
val text = doc.getText(0, doc.length)
|
||||
val firstNewline = text.indexOf('\n')
|
||||
if (firstNewline >= 0) {
|
||||
doc.remove(0, firstNewline + 1)
|
||||
}
|
||||
} catch (e: BadLocationException) {
|
||||
// Ignore errors when removing lines
|
||||
}
|
||||
}
|
||||
|
||||
fun clearConsole() {
|
||||
runInEdt {
|
||||
lineBuffer.clear()
|
||||
text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ee.carlrobert.codegpt.completions.llama.logging
|
||||
|
||||
object NoOpLoggingStrategy : ServerLoggingStrategy {
|
||||
override fun logMessage(message: String, isError: Boolean, isBuildLog: Boolean) {
|
||||
// No-op: silent logging for headless operations
|
||||
}
|
||||
|
||||
override fun setPhase(phase: String) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun startProgress() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun stopProgress() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package ee.carlrobert.codegpt.completions.llama.logging
|
||||
|
||||
interface ServerLoggingStrategy {
|
||||
fun logMessage(message: String, isError: Boolean, isBuildLog: Boolean = false)
|
||||
fun setPhase(phase: String)
|
||||
fun startProgress()
|
||||
fun stopProgress()
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package ee.carlrobert.codegpt.completions.llama.logging
|
||||
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm
|
||||
|
||||
class SettingsFormLoggingStrategy(
|
||||
private val settingsForm: LlamaSettingsForm
|
||||
) : ServerLoggingStrategy {
|
||||
|
||||
override fun logMessage(message: String, isError: Boolean, isBuildLog: Boolean) {
|
||||
settingsForm.logToConsole(message, isError, isBuildLog)
|
||||
}
|
||||
|
||||
override fun setPhase(phase: String) {
|
||||
settingsForm.updateServerStatusWithPhase(phase)
|
||||
}
|
||||
|
||||
override fun startProgress() {
|
||||
settingsForm.updateServerStatusWithPhase("Initializing...")
|
||||
}
|
||||
|
||||
override fun stopProgress() {
|
||||
settingsForm.refreshServerStatus()
|
||||
}
|
||||
}
|
||||
|
|
@ -61,10 +61,6 @@ object CredentialsStore {
|
|||
override val value: String = "ANTHROPIC_API_KEY"
|
||||
}
|
||||
|
||||
data object LlamaApiKey : CredentialKey() {
|
||||
override val value: String = "LLAMA_API_KEY"
|
||||
}
|
||||
|
||||
data object GoogleApiKey : CredentialKey() {
|
||||
override val value: String = "GOOGLE_API_KEY"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
package ee.carlrobert.codegpt.services
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.Throws
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class ExecutableRunnerService {
|
||||
|
||||
private val executorService = Executors.newCachedThreadPool()
|
||||
private val currentProcess = AtomicReference<Process?>()
|
||||
private val isRunning = AtomicBoolean(false)
|
||||
|
||||
interface ProcessOutputHandler {
|
||||
fun onStandardOutput(line: String)
|
||||
fun onErrorOutput(line: String)
|
||||
fun onProcessStarted()
|
||||
fun onProcessFinished(exitCode: Int)
|
||||
fun onProcessFailed(exception: Exception)
|
||||
}
|
||||
|
||||
fun runExecutable(
|
||||
executable: String,
|
||||
arguments: List<String>,
|
||||
workingDirectory: Path? = null,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): CompletableFuture<Int> {
|
||||
return if (isRunning.compareAndSet(false, true)) {
|
||||
CompletableFuture.supplyAsync({
|
||||
try {
|
||||
outputHandler.onProcessStarted()
|
||||
executeProcess(executable, arguments, workingDirectory, outputHandler)
|
||||
} catch (e: Exception) {
|
||||
LOG.error("Failed to execute process", e)
|
||||
outputHandler.onProcessFailed(e)
|
||||
-1
|
||||
} finally {
|
||||
isRunning.set(false)
|
||||
currentProcess.set(null)
|
||||
}
|
||||
}, executorService)
|
||||
} else {
|
||||
CompletableFuture.completedFuture(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class, InterruptedException::class)
|
||||
private fun executeProcess(
|
||||
executable: String,
|
||||
arguments: List<String>,
|
||||
workingDirectory: Path?,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): Int {
|
||||
val command = mutableListOf(executable).apply { addAll(arguments) }
|
||||
|
||||
val processBuilder = ProcessBuilder(command).apply {
|
||||
workingDirectory?.let { directory(it.toFile()) }
|
||||
redirectErrorStream(false)
|
||||
}
|
||||
|
||||
LOG.info("Executing command: ${command.joinToString(" ")}")
|
||||
|
||||
val process = processBuilder.start()
|
||||
currentProcess.set(process)
|
||||
|
||||
val streamReadingFuture = ProcessStreamReader.readProcessStreams(process, outputHandler)
|
||||
|
||||
val exitCode = process.waitFor()
|
||||
streamReadingFuture.join()
|
||||
|
||||
outputHandler.onProcessFinished(exitCode)
|
||||
|
||||
return exitCode
|
||||
}
|
||||
|
||||
fun isRunning(): Boolean = isRunning.get()
|
||||
|
||||
fun stopCurrentProcess() {
|
||||
currentProcess.get()?.let { process ->
|
||||
if (process.isAlive) {
|
||||
process.destroyForcibly()
|
||||
isRunning.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun runCommand(
|
||||
command: String,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): CompletableFuture<Int> {
|
||||
return runCommand(command, null, outputHandler)
|
||||
}
|
||||
|
||||
fun runCommand(
|
||||
command: String,
|
||||
workingDirectory: Path?,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): CompletableFuture<Int> {
|
||||
val parts = command.split("\\s+".toRegex())
|
||||
if (parts.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(-1)
|
||||
}
|
||||
|
||||
val executable = parts[0]
|
||||
val arguments = parts.drop(1)
|
||||
|
||||
return runExecutable(executable, arguments, workingDirectory, outputHandler)
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
stopCurrentProcess()
|
||||
executorService.shutdown()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(ExecutableRunnerService::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ExecutableRunnerService = project.service()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package ee.carlrobert.codegpt.services
|
||||
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import ee.carlrobert.codegpt.services.ExecutableRunnerService.ProcessOutputHandler
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
object ProcessStreamReader {
|
||||
|
||||
private val logger = thisLogger()
|
||||
|
||||
@JvmStatic
|
||||
fun readStreamAsync(
|
||||
inputStream: InputStream,
|
||||
isError: Boolean,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): CompletableFuture<Void?> {
|
||||
return CompletableFuture.runAsync {
|
||||
try {
|
||||
BufferedReader(InputStreamReader(inputStream)).use { reader ->
|
||||
reader.lineSequence().forEach { line ->
|
||||
if (isError) {
|
||||
outputHandler.onErrorOutput(line)
|
||||
} else {
|
||||
outputHandler.onStandardOutput(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
val streamType = if (isError) "stderr" else "stdout"
|
||||
logger.warn("Error reading $streamType", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun readProcessStreams(
|
||||
process: Process,
|
||||
outputHandler: ProcessOutputHandler
|
||||
): CompletableFuture<Void?> {
|
||||
val stdoutFuture = readStreamAsync(process.inputStream, false, outputHandler)
|
||||
val stderrFuture = readStreamAsync(process.errorStream, true, outputHandler)
|
||||
|
||||
return CompletableFuture.allOf(stdoutFuture, stderrFuture)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package ee.carlrobert.codegpt.services.llama
|
||||
|
||||
import com.intellij.execution.ui.ConsoleViewContentType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.MAX_LOG_ENTRIES
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaConstants.MAX_LOG_SESSIONS
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
@Service
|
||||
class ServerLogsManager {
|
||||
|
||||
private val sessions = ConcurrentHashMap<String, LogSession>()
|
||||
private val sessionOrder = CopyOnWriteArrayList<String>()
|
||||
|
||||
@Volatile
|
||||
private var currentSessionId: String? = null
|
||||
|
||||
@Synchronized
|
||||
fun startNewSession(): LogSession {
|
||||
val sessionId = UUID.randomUUID().toString()
|
||||
val session = LogSession(sessionId, LocalDateTime.now())
|
||||
|
||||
sessions[sessionId] = session
|
||||
sessionOrder.add(0, sessionId)
|
||||
currentSessionId = sessionId
|
||||
|
||||
while (sessionOrder.size > MAX_LOG_SESSIONS) {
|
||||
val oldestId = sessionOrder.removeAt(sessionOrder.size - 1)
|
||||
sessions.remove(oldestId)
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
fun getCurrentSession(): LogSession {
|
||||
val sessionId = currentSessionId
|
||||
return if (sessionId == null || !sessions.containsKey(sessionId)) {
|
||||
startNewSession()
|
||||
} else {
|
||||
sessions[sessionId]!!
|
||||
}
|
||||
}
|
||||
|
||||
fun endCurrentSession() {
|
||||
currentSessionId?.let { id ->
|
||||
sessions[id]?.endTime = LocalDateTime.now()
|
||||
}
|
||||
}
|
||||
|
||||
fun log(message: String, isError: Boolean) {
|
||||
val session = getCurrentSession()
|
||||
val contentType = if (isError) {
|
||||
ConsoleViewContentType.ERROR_OUTPUT
|
||||
} else {
|
||||
ConsoleViewContentType.NORMAL_OUTPUT
|
||||
}
|
||||
|
||||
val entry = LogEntry(LocalDateTime.now(), message, contentType)
|
||||
session.entries.add(entry)
|
||||
|
||||
while (session.entries.size > MAX_LOG_ENTRIES) {
|
||||
session.entries.removeAt(0)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllSessions(): List<LogSession> {
|
||||
return sessionOrder.mapNotNull { id -> sessions[id] }
|
||||
}
|
||||
|
||||
fun getSessionLogs(sessionId: String): List<LogEntry> {
|
||||
return sessions[sessionId]?.entries?.toList() ?: emptyList()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun clearAll() {
|
||||
sessions.clear()
|
||||
sessionOrder.clear()
|
||||
currentSessionId = null
|
||||
}
|
||||
|
||||
data class LogSession(
|
||||
val id: String,
|
||||
val startTime: LocalDateTime,
|
||||
var endTime: LocalDateTime? = null,
|
||||
val entries: MutableList<LogEntry> = CopyOnWriteArrayList()
|
||||
)
|
||||
|
||||
data class LogEntry(
|
||||
val timestamp: LocalDateTime,
|
||||
val message: String,
|
||||
val contentType: ConsoleViewContentType
|
||||
)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): ServerLogsManager = ApplicationManager.getApplication().service()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +1,46 @@
|
|||
package ee.carlrobert.codegpt.settings.service
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.options.Configurable
|
||||
import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LlamaApiKey
|
||||
import ee.carlrobert.codegpt.credentials.CredentialsStore.getCredential
|
||||
import ee.carlrobert.codegpt.credentials.CredentialsStore.setCredential
|
||||
import ee.carlrobert.codegpt.settings.GeneralSettings
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaServerAgent
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm
|
||||
import javax.swing.JComponent
|
||||
|
||||
class LlamaServiceConfigurable : Configurable {
|
||||
class LlamaServiceConfigurable : Configurable, Disposable {
|
||||
|
||||
private lateinit var component: LlamaSettingsForm
|
||||
private var form: LlamaSettingsForm? = null
|
||||
|
||||
override fun getDisplayName(): String {
|
||||
return "ProxyAI: Custom Service"
|
||||
return "CodeGPT: Llama"
|
||||
}
|
||||
|
||||
override fun createComponent(): JComponent {
|
||||
component = LlamaSettingsForm(service<LlamaSettings>().state)
|
||||
return component
|
||||
override fun createComponent(): JComponent? {
|
||||
if (form == null) {
|
||||
form = LlamaSettingsForm(LlamaSettings.getCurrentState())
|
||||
|
||||
ApplicationManager.getApplication().getService(LlamaServerAgent::class.java)
|
||||
.setSettingsForm(form)
|
||||
}
|
||||
return form
|
||||
}
|
||||
|
||||
override fun isModified(): Boolean {
|
||||
return component.getCurrentState() != service<LlamaSettings>().state
|
||||
|| component.llamaServerPreferencesForm.getApiKey() != getCredential(LlamaApiKey)
|
||||
val currentForm = form ?: return false
|
||||
return LlamaSettings.getInstance().isModified(currentForm)
|
||||
}
|
||||
|
||||
override fun apply() {
|
||||
service<GeneralSettings>().state.selectedService = ServiceType.LLAMA_CPP
|
||||
setCredential(LlamaApiKey, component.llamaServerPreferencesForm.getApiKey())
|
||||
service<LlamaSettings>().loadState(component.currentState)
|
||||
val currentForm = form ?: return
|
||||
LlamaSettings.getInstance().loadState(currentForm.currentState)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
component.resetForm()
|
||||
form?.resetForm(LlamaSettings.getCurrentState())
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
form = null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
package ee.carlrobert.codegpt.settings.service.llama.form
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.ui.MessageType
|
||||
import com.intellij.ui.PortField
|
||||
import com.intellij.ui.TitledSeparator
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.components.fields.IntegerField
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle
|
||||
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.completions.llama.logging.NoOpLoggingStrategy
|
||||
import ee.carlrobert.codegpt.completions.llama.logging.SettingsFormLoggingStrategy
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings
|
||||
import ee.carlrobert.codegpt.settings.service.llama.LlamaSettingsState
|
||||
import ee.carlrobert.codegpt.settings.service.llama.form.LlamaSettingsForm
|
||||
import ee.carlrobert.codegpt.ui.OverlayUtil
|
||||
import ee.carlrobert.codegpt.ui.UIUtil
|
||||
import javax.swing.Box
|
||||
import javax.swing.BoxLayout
|
||||
import javax.swing.JButton
|
||||
import javax.swing.JPanel
|
||||
|
||||
class LlamaServerPreferencesForm(settings: LlamaSettingsState, private val parentForm: LlamaSettingsForm? = null) {
|
||||
val llamaModelPreferencesForm = LlamaModelPreferencesForm()
|
||||
|
||||
private val portField: PortField
|
||||
private val maxTokensField: IntegerField
|
||||
private val threadsField: IntegerField
|
||||
private val additionalParametersField: JBTextField
|
||||
private val additionalBuildParametersField: JBTextField
|
||||
private val additionalEnvironmentVariablesField: JBTextField
|
||||
|
||||
init {
|
||||
val llamaServerAgent = ApplicationManager.getApplication().getService(LlamaServerAgent::class.java)
|
||||
val serverRunning = llamaServerAgent.isServerRunning
|
||||
|
||||
portField = PortField(settings.serverPort).apply {
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
|
||||
maxTokensField = IntegerField("max_tokens", 256, 4096).apply {
|
||||
columns = 12
|
||||
value = settings.contextSize
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
|
||||
threadsField = IntegerField("threads", 1, 256).apply {
|
||||
columns = 12
|
||||
value = settings.threads
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
|
||||
additionalParametersField = JBTextField(settings.additionalParameters, 30).apply {
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
|
||||
additionalBuildParametersField = JBTextField(settings.additionalBuildParameters, 30).apply {
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
|
||||
additionalEnvironmentVariablesField = JBTextField(settings.additionalEnvironmentVariables, 30).apply {
|
||||
isEnabled = !serverRunning
|
||||
}
|
||||
}
|
||||
|
||||
fun getForm(): JPanel {
|
||||
val llamaServerAgent = ApplicationManager.getApplication().getService(LlamaServerAgent::class.java)
|
||||
return createRunLocalServerForm(llamaServerAgent)
|
||||
}
|
||||
|
||||
fun resetForm(state: LlamaSettingsState) {
|
||||
llamaModelPreferencesForm.resetForm(state)
|
||||
|
||||
portField.number = state.serverPort
|
||||
maxTokensField.value = state.contextSize
|
||||
threadsField.value = state.threads
|
||||
additionalParametersField.text = state.additionalParameters
|
||||
additionalBuildParametersField.text = state.additionalBuildParameters
|
||||
additionalEnvironmentVariablesField.text = state.additionalEnvironmentVariables
|
||||
}
|
||||
|
||||
fun createRunLocalServerForm(llamaServerAgent: LlamaServerAgent): JPanel {
|
||||
return UIUtil.withEmptyLeftBorder(
|
||||
FormBuilder.createFormBuilder()
|
||||
.addComponent(
|
||||
TitledSeparator(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.modelPreferences.title")
|
||||
)
|
||||
)
|
||||
.addComponent(UIUtil.withEmptyLeftBorder(llamaModelPreferencesForm.form))
|
||||
.addComponent(TitledSeparator(CodeGPTBundle.get("llama.ui.tab.serverConfiguration")))
|
||||
.addComponent(
|
||||
UIUtil.withEmptyLeftBorder(
|
||||
FormBuilder.createFormBuilder()
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("shared.port"),
|
||||
createPortAndButtonsPanel(llamaServerAgent)
|
||||
)
|
||||
.addVerticalGap(4)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.contextSize.label"),
|
||||
maxTokensField
|
||||
)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.llama.contextSize.comment")
|
||||
)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.threads.label"),
|
||||
threadsField
|
||||
)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.llama.threads.comment")
|
||||
)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalParameters.label"),
|
||||
additionalParametersField
|
||||
)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.llama.additionalParameters.comment")
|
||||
)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalBuildParameters.label"),
|
||||
additionalBuildParametersField
|
||||
)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.llama.additionalBuildParameters.comment")
|
||||
)
|
||||
.addLabeledComponent(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.additionalEnvironmentVariables.label"),
|
||||
additionalEnvironmentVariablesField
|
||||
)
|
||||
.addComponentToRightColumn(
|
||||
UIUtil.createComment("settingsConfigurable.service.llama.additionalEnvironmentVariables.comment")
|
||||
)
|
||||
.addComponentFillVertically(JPanel(), 0)
|
||||
.panel
|
||||
)
|
||||
)
|
||||
.panel
|
||||
) as JPanel
|
||||
}
|
||||
|
||||
private fun createPortAndButtonsPanel(llamaServerAgent: LlamaServerAgent): JPanel {
|
||||
return JPanel().apply {
|
||||
layout = BoxLayout(this, BoxLayout.X_AXIS)
|
||||
add(portField)
|
||||
add(Box.createHorizontalStrut(4))
|
||||
|
||||
val serverButton = getServerButton(llamaServerAgent)
|
||||
serverButton.maximumSize = serverButton.preferredSize
|
||||
add(serverButton)
|
||||
|
||||
add(Box.createHorizontalGlue())
|
||||
}
|
||||
}
|
||||
|
||||
private fun getServerButton(llamaServerAgent: LlamaServerAgent): JButton {
|
||||
val serverRunning = llamaServerAgent.isServerRunning
|
||||
val buildInProgress = llamaServerAgent.isBuildInProgress
|
||||
|
||||
return JButton().apply {
|
||||
when {
|
||||
serverRunning -> {
|
||||
text = CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label")
|
||||
icon = AllIcons.Actions.Suspend
|
||||
}
|
||||
buildInProgress -> {
|
||||
text = CodeGPTBundle.get("llama.ui.button.stopBuild")
|
||||
icon = AllIcons.Actions.Suspend
|
||||
}
|
||||
else -> {
|
||||
text = CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label")
|
||||
icon = AllIcons.Actions.Execute
|
||||
}
|
||||
}
|
||||
|
||||
addActionListener {
|
||||
if (!validateModelConfiguration()) {
|
||||
return@addActionListener
|
||||
}
|
||||
|
||||
when {
|
||||
llamaServerAgent.isServerRunning -> {
|
||||
enableForm(this)
|
||||
llamaServerAgent.stopAgent()
|
||||
}
|
||||
llamaServerAgent.isBuildInProgress -> {
|
||||
enableForm(this)
|
||||
llamaServerAgent.stopAgent()
|
||||
}
|
||||
else -> {
|
||||
text = CodeGPTBundle.get("llama.ui.button.stopBuild")
|
||||
icon = AllIcons.Actions.Suspend
|
||||
disableForm(this)
|
||||
|
||||
llamaServerAgent.startAgent(
|
||||
LlamaServerStartupParams(
|
||||
llamaModelPreferencesForm.actualModelPath,
|
||||
contextSize,
|
||||
threads,
|
||||
serverPort,
|
||||
listOfAdditionalParameters,
|
||||
listOfAdditionalBuildParameters,
|
||||
mapOfAdditionalEnvironmentVariables
|
||||
),
|
||||
parentForm?.let {
|
||||
val strategy = SettingsFormLoggingStrategy(it)
|
||||
strategy.logMessage(CodeGPTBundle.get("llama.debug.buildLoggingStrategy"), false, true)
|
||||
strategy
|
||||
} ?: run {
|
||||
NoOpLoggingStrategy
|
||||
},
|
||||
{
|
||||
setFormEnabled(false)
|
||||
text = CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label")
|
||||
icon = AllIcons.Actions.Suspend
|
||||
},
|
||||
{
|
||||
setFormEnabled(true)
|
||||
text = CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label")
|
||||
icon = AllIcons.Actions.Execute
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateModelConfiguration(): Boolean {
|
||||
return validateCustomModelPath() && validateSelectedModel()
|
||||
}
|
||||
|
||||
private fun validateCustomModelPath(): Boolean {
|
||||
if (llamaModelPreferencesForm.isUseCustomLlamaModel) {
|
||||
val customModelPath = llamaModelPreferencesForm.customLlamaModelPath
|
||||
if (customModelPath.isNullOrEmpty()) {
|
||||
OverlayUtil.showBalloon(
|
||||
CodeGPTBundle.get("validation.error.fieldRequired"),
|
||||
MessageType.ERROR,
|
||||
llamaModelPreferencesForm.browsableCustomModelTextField
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun validateSelectedModel(): Boolean {
|
||||
if (!llamaModelPreferencesForm.isUseCustomLlamaModel &&
|
||||
!LlamaSettings.isModelExists(llamaModelPreferencesForm.selectedModel)
|
||||
) {
|
||||
OverlayUtil.showBalloon(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.overlay.modelNotDownloaded.text"),
|
||||
MessageType.ERROR,
|
||||
llamaModelPreferencesForm.huggingFaceModelComboBox
|
||||
)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun enableForm(serverButton: JButton) {
|
||||
setFormEnabled(true)
|
||||
serverButton.text = CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label")
|
||||
serverButton.icon = AllIcons.Actions.Execute
|
||||
}
|
||||
|
||||
private fun disableForm(serverButton: JButton) {
|
||||
setFormEnabled(false)
|
||||
serverButton.text = CodeGPTBundle.get("settingsConfigurable.service.llama.stopServer.label")
|
||||
serverButton.icon = AllIcons.Actions.Suspend
|
||||
}
|
||||
|
||||
private fun setFormEnabled(enabled: Boolean) {
|
||||
llamaModelPreferencesForm.enableFields(enabled)
|
||||
portField.isEnabled = enabled
|
||||
maxTokensField.isEnabled = enabled
|
||||
threadsField.isEnabled = enabled
|
||||
additionalParametersField.isEnabled = enabled
|
||||
additionalBuildParametersField.isEnabled = enabled
|
||||
additionalEnvironmentVariablesField.isEnabled = enabled
|
||||
}
|
||||
|
||||
val serverPort: Int
|
||||
get() = portField.number
|
||||
|
||||
val contextSize: Int
|
||||
get() = maxTokensField.value
|
||||
|
||||
var threads: Int
|
||||
get() = threadsField.value
|
||||
set(value) {
|
||||
threadsField.value = value
|
||||
}
|
||||
|
||||
val additionalParameters: String
|
||||
get() = additionalParametersField.text
|
||||
|
||||
val listOfAdditionalParameters: List<String>
|
||||
get() = LlamaSettings.getAdditionalParametersList(additionalParametersField.text)
|
||||
|
||||
val additionalBuildParameters: String
|
||||
get() = additionalBuildParametersField.text
|
||||
|
||||
val listOfAdditionalBuildParameters: List<String>
|
||||
get() = LlamaSettings.getAdditionalParametersList(additionalBuildParametersField.text)
|
||||
|
||||
val additionalEnvironmentVariables: String
|
||||
get() = additionalEnvironmentVariablesField.text
|
||||
|
||||
val mapOfAdditionalEnvironmentVariables: Map<String, String>
|
||||
get() = LlamaSettings.getAdditionalEnvironmentVariablesMap(additionalEnvironmentVariablesField.text)
|
||||
|
||||
val promptTemplate: PromptTemplate
|
||||
get() = llamaModelPreferencesForm.promptTemplate ?: PromptTemplate.CODE_QWEN
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package ee.carlrobert.codegpt.settings.service.llama.form
|
||||
|
||||
import com.intellij.ui.PortField
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.components.fields.IntegerField
|
||||
|
||||
data class ServerButtonConfig(
|
||||
val portField: PortField,
|
||||
val contextSizeField: IntegerField,
|
||||
val threadsField: IntegerField,
|
||||
val additionalParametersField: JBTextField,
|
||||
val additionalBuildParametersField: JBTextField,
|
||||
val additionalEnvironmentVariablesField: JBTextField
|
||||
)
|
||||
|
|
@ -72,6 +72,8 @@
|
|||
<applicationService serviceImplementation="ee.carlrobert.codegpt.settings.advanced.AdvancedSettings"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.conversations.ConversationsState"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.codecompletions.psi.CompletionContextService"/>
|
||||
<applicationService serviceImplementation="ee.carlrobert.codegpt.services.llama.ServerLogsManager"/>
|
||||
<projectService serviceImplementation="ee.carlrobert.codegpt.services.ExecutableRunnerService"/>
|
||||
<inline.completion.provider
|
||||
id="CodeGPTInlineCompletionProvider"
|
||||
implementation="ee.carlrobert.codegpt.codecompletions.DebouncedCodeCompletionProvider"/>
|
||||
|
|
|
|||
|
|
@ -147,14 +147,8 @@ configurationConfigurable.section.chatCompletion.psiStructure.title=Enable depen
|
|||
configurationConfigurable.section.chatCompletion.psiStructure.analyzeDepth.title=Code analyze depth:
|
||||
configurationConfigurable.section.chatCompletion.psiStructure.analyzeDepth.comment=The parameter limits the depth of the PSI structure traversal. Currently, it is implemented only for the Kotlin language.
|
||||
configurationConfigurable.section.chatCompletion.psiStructure.description=If enabled, the class structure that is present in the imports of the attached files will be added in the context of the dialog. A structure refers to the source code in files that include constructors, fields, and methods, with all modifiers, arguments, and return types, but without an implementation. The implementation of dependencies is intentionally excluded in order to find a balance between a high-quality chat context and saving tokens.
|
||||
settingsConfigurable.service.llama.topK.label=Top K:
|
||||
settingsConfigurable.service.llama.topK.comment=Limit the next token selection to the K most probable tokens (default: 40)
|
||||
settingsConfigurable.service.llama.topP.label=Top P:
|
||||
settingsConfigurable.service.llama.topP.comment=Limit the next token selection to a subset of tokens with a cumulative probability above a threshold P (default: 0.9)
|
||||
settingsConfigurable.service.llama.minP.label=Min P:
|
||||
settingsConfigurable.service.llama.minP.comment=Sets a minimum base probability threshold for token selection (default: 0.05)
|
||||
settingsConfigurable.service.llama.repeatPenalty.label=Repeat penalty:
|
||||
settingsConfigurable.service.llama.repeatPenalty.comment=Control the repetition of token sequences in the generated text (default: 1.1)
|
||||
settingsConfigurable.service.llama.predefinedModel.comment=Download and use vetted models from HuggingFace.
|
||||
settingsConfigurable.service.llama.customModel.comment=Use your own GGUF model file from a local path on your computer.
|
||||
settingsConfigurable.service.custom.openai.testConnection.label=Test Connection
|
||||
settingsConfigurable.service.custom.openai.presetTemplate.label=Preset template:
|
||||
settingsConfigurable.service.custom.openai.url.label=URL:
|
||||
|
|
@ -336,3 +330,33 @@ tagPopupMenuItem.closeTagsToLeft=Close Tags to the Left
|
|||
tagPopupMenuItem.closeTagsToRight=Close Tags to the Right
|
||||
toolwindow.chat.loading=Generating response...
|
||||
headerPanel.error.searchBlockNotMapped.title=Failed to Locate Search Block
|
||||
llama.build.cmake.setup=Setting up CMake...
|
||||
llama.build.cmake.build=Building project...
|
||||
llama.build.startingBuild=Starting Llama Server Build
|
||||
llama.build.phase.setup=Phase 1: CMake Setup
|
||||
llama.build.phase.build=Phase 2: Building Project
|
||||
llama.build.phase.setupFailed=CMake setup failed
|
||||
llama.build.phase.buildFailed=Build failed
|
||||
llama.build.cache.cleanup=Detected CMake cache path mismatch, cleaning up build directory...
|
||||
llama.server.buildStopped=Build stopped by user
|
||||
llama.server.starting=Starting server...
|
||||
llama.server.running=Server running successfully
|
||||
llama.server.startupFailed=Server startup failed
|
||||
llama.server.stopping.cmake=Stopping CMake setup process
|
||||
llama.server.stopping.build=Stopping build process
|
||||
llama.error.server.startup=Unable to start llama server:\n{0}
|
||||
llama.error.server.startupWithDetails=Server startup failed: {0}
|
||||
llama.ui.tab.serverConfiguration=Server Configuration
|
||||
llama.ui.tab.serverLogs=Server Logs
|
||||
llama.ui.tab.buildOutput=Build Output
|
||||
llama.ui.button.stopBuild=Stop Build
|
||||
llama.ui.status.running=Server status: Running
|
||||
llama.ui.status.building=Server status: Building...
|
||||
llama.ui.status.stopped=Server status: Stopped
|
||||
llama.ui.status.prefix=Server status: {0}
|
||||
llama.ui.action.clear=Clear
|
||||
llama.ui.action.clear.description=Clear console
|
||||
llama.ui.action.scrollToEnd=Scroll to End
|
||||
llama.ui.action.scrollToEnd.description=Scroll to bottom
|
||||
llama.process.startingBuild=Starting server build process...
|
||||
llama.debug.buildLoggingStrategy=DEBUG: Build logging strategy initialized
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue