mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-12 14:10:29 +00:00
feat: Start/stop LLaMA Server from statusbar (#544)
This commit is contained in:
parent
91c7302008
commit
7c668ae143
10 changed files with 248 additions and 84 deletions
|
|
@ -8,7 +8,6 @@ import com.intellij.openapi.extensions.PluginId;
|
|||
import com.intellij.openapi.project.Project;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class CodeGPTPlugin {
|
||||
|
|
@ -38,10 +37,6 @@ public final class CodeGPTPlugin {
|
|||
return getPluginBasePath() + File.separator + "llama.cpp";
|
||||
}
|
||||
|
||||
public static @NotNull String getLlamaModelsPath() {
|
||||
return Paths.get(System.getProperty("user.home"), ".codegpt/models/gguf").toString();
|
||||
}
|
||||
|
||||
public static @NotNull String getProjectIndexStorePath(@NotNull Project project) {
|
||||
return getIndexStorePath() + File.separator + project.getName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public final class LlamaServerAgent implements Disposable {
|
|||
LlamaServerStartupParams params,
|
||||
ServerProgressPanel serverProgressPanel,
|
||||
Runnable onSuccess,
|
||||
Consumer<ServerProgressPanel> onServerTerminated) {
|
||||
Consumer<ServerProgressPanel> onServerStopped) {
|
||||
this.activeServerProgressPanel = serverProgressPanel;
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
try {
|
||||
|
|
@ -52,10 +52,10 @@ public final class LlamaServerAgent implements Disposable {
|
|||
makeProcessHandler = new OSProcessHandler(
|
||||
getMakeCommandLine(params.additionalBuildParameters()));
|
||||
makeProcessHandler.addProcessListener(
|
||||
getMakeProcessListener(params, onSuccess, onServerTerminated));
|
||||
getMakeProcessListener(params, onSuccess, onServerStopped));
|
||||
makeProcessHandler.startNotify();
|
||||
} catch (ExecutionException e) {
|
||||
showServerError(e.getMessage(), onServerTerminated);
|
||||
showServerError(e.getMessage(), onServerStopped);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ public final class LlamaServerAgent implements Disposable {
|
|||
private ProcessListener getMakeProcessListener(
|
||||
LlamaServerStartupParams params,
|
||||
Runnable onSuccess,
|
||||
Consumer<ServerProgressPanel> onServerTerminated) {
|
||||
Consumer<ServerProgressPanel> onServerStopped) {
|
||||
LOG.info("Building llama project");
|
||||
|
||||
return new ProcessAdapter() {
|
||||
|
|
@ -103,11 +103,11 @@ public final class LlamaServerAgent implements Disposable {
|
|||
int exitCode = event.getExitCode();
|
||||
LOG.info(format("Server build exited with code %d", exitCode));
|
||||
if (stoppedByUser) {
|
||||
onServerTerminated.accept(activeServerProgressPanel);
|
||||
onServerStopped.accept(activeServerProgressPanel);
|
||||
return;
|
||||
}
|
||||
if (exitCode != 0) {
|
||||
showServerError(String.join(",", errorLines), onServerTerminated);
|
||||
showServerError(String.join(",", errorLines), onServerStopped);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +118,10 @@ public final class LlamaServerAgent implements Disposable {
|
|||
CodeGPTBundle.get("llamaServerAgent.serverBootup.description"));
|
||||
startServerProcessHandler = new OSProcessHandler.Silent(getServerCommandLine(params));
|
||||
startServerProcessHandler.addProcessListener(
|
||||
getProcessListener(params.port(), onSuccess,
|
||||
onServerTerminated));
|
||||
getProcessListener(params.port(), onSuccess, onServerStopped));
|
||||
startServerProcessHandler.startNotify();
|
||||
} catch (ExecutionException ex) {
|
||||
showServerError(ex.getMessage(), onServerTerminated);
|
||||
showServerError(ex.getMessage(), onServerStopped);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -131,18 +130,18 @@ public final class LlamaServerAgent implements Disposable {
|
|||
private ProcessListener getProcessListener(
|
||||
int port,
|
||||
Runnable onSuccess,
|
||||
Consumer<ServerProgressPanel> onServerTerminated) {
|
||||
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 terminated with code %d", event.getExitCode()));
|
||||
LOG.info(format("Server stopped with code %d", event.getExitCode()));
|
||||
if (stoppedByUser) {
|
||||
onServerTerminated.accept(activeServerProgressPanel);
|
||||
onServerStopped.accept(activeServerProgressPanel);
|
||||
} else {
|
||||
showServerError(String.join(",", errorLines), onServerTerminated);
|
||||
showServerError(String.join(",", errorLines), onServerStopped);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +171,8 @@ public final class LlamaServerAgent implements Disposable {
|
|||
};
|
||||
}
|
||||
|
||||
private void showServerError(String errorText, Consumer<ServerProgressPanel> onServerTerminated) {
|
||||
onServerTerminated.accept(activeServerProgressPanel);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package ee.carlrobert.codegpt.settings.service.llama;
|
||||
|
||||
import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LLAMA_API_KEY;
|
||||
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;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
|
|
@ -10,7 +13,13 @@ import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
|
|||
import ee.carlrobert.codegpt.completions.HuggingFaceModel;
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaModel;
|
||||
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;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -64,4 +73,37 @@ public class LlamaSettings implements PersistentStateComponent<LlamaSettingsStat
|
|||
form.getLlamaServerPreferencesForm().getApiKey(),
|
||||
CredentialsStore.getCredential(LLAMA_API_KEY));
|
||||
}
|
||||
|
||||
public static boolean isRunnable() {
|
||||
return (IS_OS_MAC_OSX || IS_OS_LINUX)
|
||||
&& GeneralSettings.getCurrentState().getSelectedService() == LLAMA_CPP;
|
||||
}
|
||||
|
||||
public static boolean isRunnable(HuggingFaceModel model) {
|
||||
return isRunnable() && isModelExists(model);
|
||||
}
|
||||
|
||||
public static boolean isModelExists(HuggingFaceModel model) {
|
||||
return getLlamaModelsPath().resolve(model.getFileName()).toFile().exists();
|
||||
}
|
||||
|
||||
public static Path getLlamaModelsPath() {
|
||||
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.getHuggingFaceModel().getFileName();
|
||||
}
|
||||
|
||||
public static List<String> getAdditionalParametersList(String additionalParameters) {
|
||||
return Arrays.stream(additionalParameters.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isBlank())
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package ee.carlrobert.codegpt.settings.service.llama.form;
|
||||
|
||||
import static ee.carlrobert.codegpt.settings.service.llama.LlamaSettings.getLlamaModelsPath;
|
||||
import static ee.carlrobert.codegpt.settings.service.llama.LlamaSettings.isModelExists;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.emptyMap;
|
||||
|
||||
|
|
@ -15,7 +17,6 @@ import com.intellij.openapi.ui.ComboBox;
|
|||
import com.intellij.openapi.ui.TextBrowseFolderListener;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.ui.panel.ComponentPanelBuilder;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.ui.EnumComboBoxModel;
|
||||
import com.intellij.ui.components.AnActionLink;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
|
|
@ -23,7 +24,6 @@ import com.intellij.ui.components.JBRadioButton;
|
|||
import com.intellij.util.ui.FormBuilder;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import ee.carlrobert.codegpt.CodeGPTBundle;
|
||||
import ee.carlrobert.codegpt.CodeGPTPlugin;
|
||||
import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
|
||||
import ee.carlrobert.codegpt.completions.HuggingFaceModel;
|
||||
import ee.carlrobert.codegpt.completions.llama.LlamaModel;
|
||||
|
|
@ -37,7 +37,6 @@ import java.awt.CardLayout;
|
|||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
|
|
@ -100,7 +99,7 @@ public class LlamaModelPreferencesForm {
|
|||
.filter(model -> model.getParameterSize() == llm.getParameterSize())
|
||||
.toList();
|
||||
huggingFaceComboBoxModel.addAll(selectableModels);
|
||||
huggingFaceComboBoxModel.setSelectedItem(selectableModels.get(0));
|
||||
huggingFaceComboBoxModel.setSelectedItem(llm);
|
||||
downloadModelActionLinkWrapper = new JPanel(new BorderLayout());
|
||||
downloadModelActionLinkWrapper.setBorder(JBUI.Borders.emptyLeft(2));
|
||||
downloadModelActionLinkWrapper.add(
|
||||
|
|
@ -116,7 +115,10 @@ public class LlamaModelPreferencesForm {
|
|||
var modelSizeComboBoxModel = new DefaultComboBoxModel<ModelSize>();
|
||||
var initialModelSizes = llamaModel.getSortedUniqueModelSizes();
|
||||
modelSizeComboBoxModel.addAll(initialModelSizes);
|
||||
modelSizeComboBoxModel.setSelectedItem(initialModelSizes.get(0));
|
||||
var selectedModelSize = initialModelSizes.stream()
|
||||
.filter(ms -> ms.size() == llm.getParameterSize())
|
||||
.findFirst().orElse(initialModelSizes.get(0));
|
||||
modelSizeComboBoxModel.setSelectedItem(selectedModelSize);
|
||||
var modelComboBoxModel = new EnumComboBoxModel<>(LlamaModel.class);
|
||||
modelComboBox = createModelComboBox(modelComboBoxModel, llamaModel, modelSizeComboBoxModel);
|
||||
modelComboBox.setEnabled(!llamaServerAgent.isServerRunning());
|
||||
|
|
@ -194,7 +196,7 @@ public class LlamaModelPreferencesForm {
|
|||
public String getActualModelPath() {
|
||||
return isUseCustomLlamaModel()
|
||||
? getCustomLlamaModelPath()
|
||||
: CodeGPTPlugin.getLlamaModelsPath() + File.separator + getSelectedModel().getFileName();
|
||||
: getLlamaModelsPath().resolve(getSelectedModel().getFileName()).toString();
|
||||
}
|
||||
|
||||
private JPanel createFormPanelCards() {
|
||||
|
|
@ -386,11 +388,6 @@ public class LlamaModelPreferencesForm {
|
|||
return browseButton;
|
||||
}
|
||||
|
||||
private boolean isModelExists(HuggingFaceModel model) {
|
||||
return FileUtil.exists(
|
||||
CodeGPTPlugin.getLlamaModelsPath() + File.separator + model.getFileName());
|
||||
}
|
||||
|
||||
private AnActionLink createCancelDownloadLink(
|
||||
JBLabel progressLabel,
|
||||
JPanel actionLinkWrapper,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package ee.carlrobert.codegpt.settings.service.llama.form;
|
||||
|
||||
import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LLAMA_API_KEY;
|
||||
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;
|
||||
|
|
@ -9,7 +10,6 @@ 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.openapi.util.io.FileUtil;
|
||||
import com.intellij.ui.PortField;
|
||||
import com.intellij.ui.TitledSeparator;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
|
|
@ -21,20 +21,17 @@ 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.CodeGPTPlugin;
|
||||
import ee.carlrobert.codegpt.codecompletions.InfillPromptTemplate;
|
||||
import ee.carlrobert.codegpt.completions.HuggingFaceModel;
|
||||
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 java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.swing.JButton;
|
||||
|
|
@ -254,7 +251,7 @@ public class LlamaServerPreferencesForm {
|
|||
CodeGPTBundle.get("settingsConfigurable.service.llama.startServer.label"));
|
||||
serverButton.setIcon(Actions.Execute);
|
||||
activeServerProgressPanel.displayComponent(new JBLabel(
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.serverTerminated"),
|
||||
CodeGPTBundle.get("settingsConfigurable.service.llama.progress.serverStopped"),
|
||||
Actions.Cancel,
|
||||
SwingConstants.LEADING));
|
||||
});
|
||||
|
|
@ -293,11 +290,6 @@ public class LlamaServerPreferencesForm {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean isModelExists(HuggingFaceModel model) {
|
||||
return FileUtil.exists(
|
||||
CodeGPTPlugin.getLlamaModelsPath() + File.separator + model.getFileName());
|
||||
}
|
||||
|
||||
private void enableForm(JButton serverButton, ServerProgressPanel progressPanel) {
|
||||
setFormEnabled(true);
|
||||
serverButton.setText(
|
||||
|
|
@ -358,10 +350,7 @@ public class LlamaServerPreferencesForm {
|
|||
}
|
||||
|
||||
public List<String> getListOfAdditionalParameters() {
|
||||
return Arrays.stream(additionalParametersField.getText().split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isBlank())
|
||||
.toList();
|
||||
return LlamaSettings.getAdditionalParametersList(additionalParametersField.getText());
|
||||
}
|
||||
|
||||
public String getAdditionalBuildParameters() {
|
||||
|
|
@ -369,10 +358,7 @@ public class LlamaServerPreferencesForm {
|
|||
}
|
||||
|
||||
public List<String> getListOfAdditionalBuildParameters() {
|
||||
return Arrays.stream(additionalBuildParametersField.getText().split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isBlank())
|
||||
.toList();
|
||||
return LlamaSettings.getAdditionalParametersList(additionalBuildParametersField.getText());
|
||||
}
|
||||
|
||||
public PromptTemplate getPromptTemplate() {
|
||||
|
|
|
|||
|
|
@ -31,15 +31,38 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
public class OverlayUtil {
|
||||
|
||||
public static final String NOTIFICATION_GROUP_ID = "CodeGPT Notification Group";
|
||||
public static final String NOTIFICATION_GROUP_STICKY_ID = "CodeGPT Notification Group Sticky";
|
||||
|
||||
private OverlayUtil() {
|
||||
}
|
||||
|
||||
public static Notification getDefaultNotification(String content, NotificationType type) {
|
||||
return new Notification("CodeGPT Notification Group", "CodeGPT", content, type);
|
||||
return new Notification(NOTIFICATION_GROUP_ID, "CodeGPT", content, type);
|
||||
}
|
||||
|
||||
public static void showNotification(String content, NotificationType type) {
|
||||
Notifications.Bus.notify(getDefaultNotification(content, type));
|
||||
public static Notification getStickyNotification(String content, NotificationType type) {
|
||||
return new Notification(NOTIFICATION_GROUP_STICKY_ID, "CodeGPT", content, type);
|
||||
}
|
||||
|
||||
public static Notification showNotification(String content) {
|
||||
return showNotification(content, NotificationType.INFORMATION);
|
||||
}
|
||||
|
||||
public static Notification showNotification(String content, NotificationType type) {
|
||||
var notification = getDefaultNotification(content, type);
|
||||
Notifications.Bus.notify(notification);
|
||||
return notification;
|
||||
}
|
||||
|
||||
public static Notification stickyNotification(String content) {
|
||||
return stickyNotification(content, NotificationType.INFORMATION);
|
||||
}
|
||||
|
||||
public static Notification stickyNotification(String content, NotificationType type) {
|
||||
var notification = getStickyNotification(content, type);
|
||||
Notifications.Bus.notify(notification);
|
||||
return notification;
|
||||
}
|
||||
|
||||
public static int showDeleteConversationDialog() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue