initial commit
This commit is contained in:
1
apps.json
Normal file
1
apps.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"apps":[{"path":"file:///home/sb/lm/koboldcpp-rocm/koboldcpp.py","interpreter":"file:///usr/bin/python","arguments":[],"appArguments":[{"argument":"--usecublas","optional":true,"default_":true},{"argument":"mmq","optional":true,"default_":false},{"argument":"lowvram","optional":true,"default_":false},{"argument":"0","optional":true,"default_":true},{"argument":"--gpulayers","optional":true,"default_":true},{"argument":"GPU_LAYERS","optional":true,"default_":true},{"argument":"--smartcontext","optional":true,"default_":false},{"argument":"--noshift","optional":true,"default_":false},{"argument":"--contextsize","optional":false,"default_":true},{"argument":"CONTEXT_SIZE","optional":false,"default_":true},{"argument":"--launch","optional":false,"default_":true},{"argument":"--host","optional":true,"default_":false},{"argument":"0.0.0.0","optional":true,"default_":false},{"argument":"--threads","optional":false,"default_":true},{"argument":"THREADS","optional":false,"default_":true},{"argument":"--model","optional":false,"default_":true},{"argument":"MODEL","optional":false,"default_":true}]},{"path":"file:///home/sb/lm/llama.cpp/llama-server","interpreter":null,"arguments":[],"appArguments":[{"argument":"-nkvo","optional":true,"default_":false},{"argument":"--parallel","optional":true,"default_":false},{"argument":"2","optional":true,"default_":false},{"argument":"4","optional":true,"default_":false},{"argument":"--host","optional":true,"default_":true},{"argument":"0.0.0.0","optional":true,"default_":true},{"argument":"--port","optional":false,"default_":true},{"argument":"5001","optional":false,"default_":true},{"argument":"-t","optional":false,"default_":true},{"argument":"THREADS","optional":false,"default_":true},{"argument":"-ngl","optional":false,"default_":true},{"argument":"GPU_LAYERS","optional":false,"default_":true},{"argument":"--ctx-size","optional":false,"default_":true},{"argument":"CONTEXT_SIZE","optional":false,"default_":true},{"argument":"-m","optional":false,"default_":true},{"argument":"MODEL","optional":false,"default_":true}]},{"path":"file:///home/sb/lm/SillyTavern/start.sh","interpreter":null,"arguments":[],"appArguments":[]}]}
|
||||||
BIN
jackson-annotations-2.17.2.jar
Normal file
BIN
jackson-annotations-2.17.2.jar
Normal file
Binary file not shown.
BIN
jackson-core-2.17.2.jar
Normal file
BIN
jackson-core-2.17.2.jar
Normal file
Binary file not shown.
BIN
jackson-databind-2.17.2.jar
Normal file
BIN
jackson-databind-2.17.2.jar
Normal file
Binary file not shown.
BIN
lm-launcher.jar
Normal file
BIN
lm-launcher.jar
Normal file
Binary file not shown.
2
lm-launcher.properties
Normal file
2
lm-launcher.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
models=/home/sb/lm/models/
|
||||||
|
console=/usr/bin/konsole -e CMD
|
||||||
1
models.json
Normal file
1
models.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"models":[{"path":"/home/sb/lm/models/Meta-Llama-3.1-8B-Instruct-Q8_0.gguf","contextSize":32768,"maxContextSize":32768,"gpuLayers":99,"threads":6,"promptTemplate":"llama-3"}]}
|
||||||
61
src/de/extio/lm_launcher/App.java
Normal file
61
src/de/extio/lm_launcher/App.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
record App(Path path, Path interpreter, @Deprecated List<String> arguments, List<AppArgument> appArguments) {
|
||||||
|
|
||||||
|
static Map<String, Function<Model, String>> PLACEHOLDERS = Map.of(
|
||||||
|
"MODEL", m -> m.path(),
|
||||||
|
"CONTEXT_SIZE", m -> String.valueOf(m.contextSize()),
|
||||||
|
"THREADS", m -> String.valueOf(m.threads()),
|
||||||
|
"GPU_LAYERS", m -> String.valueOf(m.gpuLayers()));
|
||||||
|
|
||||||
|
String argumentsToString(boolean showAll) {
|
||||||
|
return this.argumentsToStringByArgs(this.appArguments.stream(), showAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
String argumentsToString(final List<AppArgument> argumentOverrides, boolean showAll) {
|
||||||
|
return this.argumentsToStringByArgs(this.appArguments
|
||||||
|
.stream()
|
||||||
|
.map(arg -> argumentOverrides.stream().filter(a -> a.argument().equals(arg.argument())).findFirst().orElse(arg)),
|
||||||
|
showAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String argumentsToStringByArgs(final Stream<AppArgument> args, boolean showAll) {
|
||||||
|
return args
|
||||||
|
.filter(arg -> showAll || (arg.optional() ? arg.default_() : true))
|
||||||
|
.map(AppArgument::argument)
|
||||||
|
.collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(final Model model, final List<AppArgument> argumentOverrides) throws IOException, IllegalArgumentException {
|
||||||
|
String interpreterStr = "";
|
||||||
|
if (this.interpreter() != null) {
|
||||||
|
interpreterStr = this.interpreter().toString().concat(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
String consoleCmdStr = Data.props.getProperty("console")
|
||||||
|
.replace("CMD", interpreterStr + this.path().toString() + " " + this.argumentsToString(argumentOverrides, false));
|
||||||
|
|
||||||
|
if (PLACEHOLDERS.keySet().stream().anyMatch(consoleCmdStr::contains)) {
|
||||||
|
if (model == null) {
|
||||||
|
throw new IllegalArgumentException("Select a model first");
|
||||||
|
}
|
||||||
|
for (final Entry<String, Function<Model, String>> placeholder : PLACEHOLDERS.entrySet()) {
|
||||||
|
consoleCmdStr = consoleCmdStr.replace(placeholder.getKey(), placeholder.getValue().apply(model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime.getRuntime().exec(
|
||||||
|
consoleCmdStr.split("\\s+"),
|
||||||
|
null,
|
||||||
|
this.path().toAbsolutePath().getParent().toFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/de/extio/lm_launcher/AppArgument.java
Normal file
5
src/de/extio/lm_launcher/AppArgument.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
public record AppArgument(String argument, boolean optional, boolean default_) {
|
||||||
|
|
||||||
|
}
|
||||||
222
src/de/extio/lm_launcher/AppPropertiesDialog.java
Normal file
222
src/de/extio/lm_launcher/AppPropertiesDialog.java
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Frame;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EventObject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.AbstractCellEditor;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
import javax.swing.table.TableCellEditor;
|
||||||
|
import javax.swing.table.TableCellRenderer;
|
||||||
|
|
||||||
|
public class AppPropertiesDialog extends JDialog {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JPanel contentPanel = new JPanel();
|
||||||
|
|
||||||
|
JTextField textField;
|
||||||
|
|
||||||
|
JScrollPane scrollPane;
|
||||||
|
|
||||||
|
JTable table;
|
||||||
|
|
||||||
|
DefaultTableModel model = new DefaultTableModel();
|
||||||
|
|
||||||
|
JPanel panel;
|
||||||
|
|
||||||
|
JLabel lblNewLabel;
|
||||||
|
|
||||||
|
JButton btnUpdate;
|
||||||
|
|
||||||
|
static App app;
|
||||||
|
|
||||||
|
private final Runnable onClose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the dialog.
|
||||||
|
*/
|
||||||
|
public AppPropertiesDialog(final Frame parent, final App app, final Runnable onClose) {
|
||||||
|
super(parent);
|
||||||
|
|
||||||
|
AppPropertiesDialog.app = app;
|
||||||
|
this.onClose = onClose;
|
||||||
|
|
||||||
|
this.setBounds(100, 100, 681, 350);
|
||||||
|
this.getContentPane().setLayout(new BorderLayout());
|
||||||
|
this.contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
this.getContentPane().add(this.contentPanel, BorderLayout.CENTER);
|
||||||
|
this.contentPanel.setLayout(new BorderLayout(0, 0));
|
||||||
|
{
|
||||||
|
this.scrollPane = new JScrollPane();
|
||||||
|
this.contentPanel.add(this.scrollPane, BorderLayout.CENTER);
|
||||||
|
{
|
||||||
|
this.model.addColumn("Parameter");
|
||||||
|
this.model.addColumn("Optional");
|
||||||
|
this.model.addColumn("Default");
|
||||||
|
|
||||||
|
this.table = new JTable(this.model);
|
||||||
|
this.table.setRowSelectionAllowed(false);
|
||||||
|
this.table.setFillsViewportHeight(true);
|
||||||
|
this.table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||||
|
|
||||||
|
JCheckBoxRenderer renderer = new JCheckBoxRenderer();
|
||||||
|
JCheckBoxEditor editor = new JCheckBoxEditor();
|
||||||
|
this.table.getColumnModel().getColumn(1).setCellRenderer(renderer);
|
||||||
|
this.table.getColumnModel().getColumn(1).setCellEditor(editor);
|
||||||
|
renderer = new JCheckBoxRenderer();
|
||||||
|
editor = new JCheckBoxEditor();
|
||||||
|
this.table.getColumnModel().getColumn(2).setCellRenderer(renderer);
|
||||||
|
this.table.getColumnModel().getColumn(2).setCellEditor(editor);
|
||||||
|
|
||||||
|
this.scrollPane.setViewportView(this.table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.panel = new JPanel();
|
||||||
|
this.contentPanel.add(this.panel, BorderLayout.NORTH);
|
||||||
|
this.panel.setLayout(new BorderLayout(0, 0));
|
||||||
|
{
|
||||||
|
this.textField = new JTextField();
|
||||||
|
this.panel.add(this.textField);
|
||||||
|
this.textField.setColumns(10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblNewLabel = new JLabel("Enter the arguments. Placeholders: " + String.join(", ", App.PLACEHOLDERS.keySet()));
|
||||||
|
this.panel.add(this.lblNewLabel, BorderLayout.NORTH);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnUpdate = new JButton("Update");
|
||||||
|
this.btnUpdate.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
AppPropertiesDialog.this.refreshTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel.add(this.btnUpdate, BorderLayout.EAST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final JPanel buttonPane = new JPanel();
|
||||||
|
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
this.getContentPane().add(buttonPane, BorderLayout.SOUTH);
|
||||||
|
{
|
||||||
|
final JButton okButton = new JButton("OK");
|
||||||
|
okButton.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
AppPropertiesDialog.this.setVisible(false);
|
||||||
|
AppPropertiesDialog.this.onClose.run();
|
||||||
|
AppPropertiesDialog.this.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
okButton.setActionCommand("OK");
|
||||||
|
buttonPane.add(okButton);
|
||||||
|
this.getRootPane().setDefaultButton(okButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textField.setText(app.argumentsToString(true));
|
||||||
|
|
||||||
|
this.refreshTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshTable() {
|
||||||
|
this.model.setRowCount(0);
|
||||||
|
|
||||||
|
final List<String> arguments = Arrays.asList(this.textField.getText().split("\\s+"));
|
||||||
|
final List<AppArgument> appArgs = new ArrayList<>();
|
||||||
|
for (int i = 0; i < arguments.size(); i++) {
|
||||||
|
final String argument = arguments.get(i);
|
||||||
|
if (argument.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final long existingRecords = AppPropertiesDialog.app.appArguments().stream().filter(arg -> arg.argument().equals(argument)).count() - 1;
|
||||||
|
final long newRecordIndex = appArgs.stream().filter(arg -> arg.argument().equals(argument)).count();
|
||||||
|
|
||||||
|
final AppArgument appArgument = AppPropertiesDialog.app.appArguments()
|
||||||
|
.stream()
|
||||||
|
.filter(arg -> arg.argument().equals(argument))
|
||||||
|
.skip(Math.max(0, Math.min(newRecordIndex, existingRecords)))
|
||||||
|
.findFirst()
|
||||||
|
.orElseGet(() -> new AppArgument(argument, false, true));
|
||||||
|
appArgs.add(appArgument);
|
||||||
|
|
||||||
|
this.model.addRow(new Object[] { appArgument.argument(), appArgument.optional(), appArgument.default_() });
|
||||||
|
}
|
||||||
|
|
||||||
|
AppPropertiesDialog.app.appArguments().clear();
|
||||||
|
AppPropertiesDialog.app.appArguments().addAll(appArgs);
|
||||||
|
|
||||||
|
this.table.revalidate();
|
||||||
|
this.table.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class JCheckBoxRenderer extends JCheckBox implements TableCellRenderer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
|
||||||
|
this.setSelected((boolean) value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class JCheckBoxEditor extends AbstractCellEditor implements TableCellEditor {
|
||||||
|
|
||||||
|
private final JCheckBox checkBox = new JCheckBox() {
|
||||||
|
|
||||||
|
{
|
||||||
|
this.addActionListener(e -> {
|
||||||
|
final AppArgument existing = AppPropertiesDialog.app.appArguments().get(JCheckBoxEditor.this.row);
|
||||||
|
if (JCheckBoxEditor.this.column == 1) {
|
||||||
|
AppPropertiesDialog.app.appArguments().set(JCheckBoxEditor.this.row, new AppArgument(existing.argument(), this.isSelected(), existing.default_()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AppPropertiesDialog.app.appArguments().set(JCheckBoxEditor.this.row, new AppArgument(existing.argument(), existing.optional(), this.isSelected()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private int row;
|
||||||
|
|
||||||
|
private int column;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {
|
||||||
|
this.row = row;
|
||||||
|
this.column = column;
|
||||||
|
this.checkBox.setSelected((Boolean) value);
|
||||||
|
return this.checkBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCellEditorValue() {
|
||||||
|
return this.checkBox.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCellEditable(final EventObject e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/de/extio/lm_launcher/Data.java
Normal file
115
src/de/extio/lm_launcher/Data.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
public class Data {
|
||||||
|
|
||||||
|
static final Properties props;
|
||||||
|
|
||||||
|
static ModelData modelData;
|
||||||
|
|
||||||
|
static AppData appData;
|
||||||
|
|
||||||
|
static {
|
||||||
|
props = new Properties();
|
||||||
|
try {
|
||||||
|
props.load(new FileInputStream("lm-launcher.properties"));
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
modelData = objectMapper.readValue(new File("models.json"), ModelData.class);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (modelData == null || modelData.models == null) {
|
||||||
|
modelData = new ModelData(new ArrayList<>());
|
||||||
|
}
|
||||||
|
// Migration
|
||||||
|
for (int i = 0; i < modelData.models().size(); i++) {
|
||||||
|
final Model model = modelData.models.get(i);
|
||||||
|
if (model.maxContextSize() < model.contextSize() || model.promptTemplate() == null) {
|
||||||
|
modelData.models.set(i, new Model(model.path(), model.contextSize(), model.contextSize(), model.gpuLayers(), model.threads(), Objects.requireNonNullElse(model.promptTemplate(), "")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
appData = objectMapper.readValue(new File("apps.json"), AppData.class);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (appData == null || appData.apps == null) {
|
||||||
|
appData = new AppData(new ArrayList<>());
|
||||||
|
}
|
||||||
|
// Migration
|
||||||
|
for (int i = 0; i < appData.apps.size(); i++) {
|
||||||
|
final App app = appData.apps.get(i);
|
||||||
|
if (app.appArguments() == null) {
|
||||||
|
final List<AppArgument> arguments = new ArrayList<>(app.arguments().size());
|
||||||
|
app.arguments().stream().map(argument -> new AppArgument(argument, false, true)).forEach(arguments::add);
|
||||||
|
appData.apps.set(i, new App(app.path(), app.interpreter(), new ArrayList<>(), arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveModels() {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
try {
|
||||||
|
objectMapper.writeValue(new File("models.json"), modelData);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveApps() {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
try {
|
||||||
|
objectMapper.writeValue(new File("apps.json"), appData);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<String> scanModels() {
|
||||||
|
final List<String> result = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
Files
|
||||||
|
.list(Path.of(props.getProperty("models")))
|
||||||
|
.filter(p -> p.getFileName().toString().endsWith(".gguf"))
|
||||||
|
.map(Path::toAbsolutePath)
|
||||||
|
.map(Path::toString)
|
||||||
|
.sorted()
|
||||||
|
.forEach(result::add);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static record ModelData(List<Model> models) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static record AppData(List<App> apps) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
609
src/de/extio/lm_launcher/LaunchFrame.java
Normal file
609
src/de/extio/lm_launcher/LaunchFrame.java
Normal file
@@ -0,0 +1,609 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.AbstractCellEditor;
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.DefaultListSelectionModel;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JSlider;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.WindowConstants;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
import javax.swing.table.TableCellEditor;
|
||||||
|
import javax.swing.table.TableCellRenderer;
|
||||||
|
|
||||||
|
public class LaunchFrame extends JFrame {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JPanel contentPane;
|
||||||
|
|
||||||
|
JPanel panel;
|
||||||
|
|
||||||
|
JPanel panel_1;
|
||||||
|
|
||||||
|
JButton btnAdd;
|
||||||
|
|
||||||
|
JButton btnEdit;
|
||||||
|
|
||||||
|
JSplitPane splitPane;
|
||||||
|
|
||||||
|
JScrollPane scrollPane;
|
||||||
|
|
||||||
|
JScrollPane scrollPane_1;
|
||||||
|
|
||||||
|
JList list;
|
||||||
|
|
||||||
|
JList list_1;
|
||||||
|
|
||||||
|
JButton btnDelete;
|
||||||
|
|
||||||
|
JButton btnClone;
|
||||||
|
|
||||||
|
JPanel panel_2;
|
||||||
|
|
||||||
|
JButton btnAdd_1;
|
||||||
|
|
||||||
|
JButton btnEdit_1;
|
||||||
|
|
||||||
|
JButton btnDelete_1;
|
||||||
|
|
||||||
|
JButton btnClone_1;
|
||||||
|
|
||||||
|
JButton btnRun_1;
|
||||||
|
|
||||||
|
DefaultListModel<String> listModel;
|
||||||
|
|
||||||
|
DefaultListModel<String> list1Model;
|
||||||
|
|
||||||
|
Component horizontalStrut;
|
||||||
|
|
||||||
|
JSplitPane splitPane_1;
|
||||||
|
|
||||||
|
JScrollPane scrollPane_2;
|
||||||
|
|
||||||
|
JTable table;
|
||||||
|
|
||||||
|
DefaultTableModel appArgumentsTableModel = new DefaultTableModel() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCellEditable(final int row, final int column) {
|
||||||
|
return ((AppArgument) this.getValueAt(row, column)).optional();
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
JSplitPane splitPane_2;
|
||||||
|
|
||||||
|
JPanel panel_3;
|
||||||
|
|
||||||
|
JSlider slider_context;
|
||||||
|
|
||||||
|
JLabel lblContextLength;
|
||||||
|
|
||||||
|
Component verticalStrut;
|
||||||
|
|
||||||
|
JLabel lblThreads;
|
||||||
|
|
||||||
|
JSlider slider_threads;
|
||||||
|
|
||||||
|
JLabel lblGpuLayers;
|
||||||
|
|
||||||
|
JSlider slider_gpu;
|
||||||
|
|
||||||
|
JLabel lblPromptTemplate;
|
||||||
|
|
||||||
|
JLabel lblPromptTemplate_1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the frame.
|
||||||
|
*/
|
||||||
|
public LaunchFrame() {
|
||||||
|
this.setTitle("LM Launcher");
|
||||||
|
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
|
this.setBounds(100, 100, 400, 400);
|
||||||
|
this.setPreferredSize(new Dimension(650, 650));
|
||||||
|
this.contentPane = new JPanel();
|
||||||
|
this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
this.setContentPane(this.contentPane);
|
||||||
|
this.contentPane.setLayout(new BorderLayout(0, 0));
|
||||||
|
{
|
||||||
|
this.panel = new JPanel();
|
||||||
|
this.contentPane.add(this.panel, BorderLayout.SOUTH);
|
||||||
|
{
|
||||||
|
this.btnAdd = new JButton("Add");
|
||||||
|
this.btnAdd.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final SelectModelDialog smDialog = new SelectModelDialog(LaunchFrame.this, path -> {
|
||||||
|
final ModelPropertiesDialog mpDialog = new ModelPropertiesDialog(LaunchFrame.this, path, null, model -> {
|
||||||
|
Data.modelData.models().add(model);
|
||||||
|
Data.modelData.models().sort((o1, o2) -> {
|
||||||
|
return o1.path().compareTo(o2.path());
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
Data.saveModels();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mpDialog.setLocationRelativeTo(LaunchFrame.this);
|
||||||
|
mpDialog.setVisible(true);
|
||||||
|
});
|
||||||
|
smDialog.setLocationRelativeTo(LaunchFrame.this);
|
||||||
|
smDialog.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel.add(this.btnAdd);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnEdit = new JButton("Edit");
|
||||||
|
this.btnEdit.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list_1.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select a model first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Model editModel = Data.modelData.models().get(index);
|
||||||
|
final ModelPropertiesDialog mpDialog = new ModelPropertiesDialog(LaunchFrame.this, editModel.path(), editModel, model -> {
|
||||||
|
Data.modelData.models().set(index, model);
|
||||||
|
try {
|
||||||
|
Data.saveModels();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mpDialog.setLocationRelativeTo(LaunchFrame.this);
|
||||||
|
mpDialog.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel.add(this.btnEdit);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnDelete = new JButton("Delete");
|
||||||
|
this.btnDelete.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list_1.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select a model first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Data.modelData.models().remove(index);
|
||||||
|
try {
|
||||||
|
Data.saveModels();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel.add(this.btnDelete);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnClone = new JButton("Clone");
|
||||||
|
this.btnClone.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list_1.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select a model first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Model model = Data.modelData.models().get(index);
|
||||||
|
Data.modelData.models().add(index, new Model(model.path(), model.contextSize(), model.maxContextSize(), model.gpuLayers(), model.threads(), model.promptTemplate()));
|
||||||
|
try {
|
||||||
|
Data.saveModels();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel.add(this.btnClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.panel_1 = new JPanel();
|
||||||
|
this.contentPane.add(this.panel_1, BorderLayout.CENTER);
|
||||||
|
this.panel_1.setLayout(new BorderLayout(0, 0));
|
||||||
|
{
|
||||||
|
this.splitPane = new JSplitPane();
|
||||||
|
this.splitPane.setResizeWeight(0.5);
|
||||||
|
this.splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
|
||||||
|
this.panel_1.add(this.splitPane);
|
||||||
|
{
|
||||||
|
this.splitPane_1 = new JSplitPane();
|
||||||
|
this.splitPane_1.setResizeWeight(0.75);
|
||||||
|
this.splitPane.setLeftComponent(this.splitPane_1);
|
||||||
|
this.scrollPane = new JScrollPane();
|
||||||
|
this.splitPane_1.setLeftComponent(this.scrollPane);
|
||||||
|
|
||||||
|
this.listModel = new DefaultListModel<>();
|
||||||
|
this.list = new JList(this.listModel);
|
||||||
|
this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
this.list.getSelectionModel().addListSelectionListener(e -> {
|
||||||
|
if (!e.getValueIsAdjusting()) {
|
||||||
|
if (this.table.getCellEditor() != null) {
|
||||||
|
this.table.getCellEditor().stopCellEditing();
|
||||||
|
}
|
||||||
|
this.appArgumentsTableModel.setRowCount(0);
|
||||||
|
final DefaultListSelectionModel selectionModel = (DefaultListSelectionModel) e.getSource();
|
||||||
|
if (selectionModel.getMinSelectionIndex() > -1) {
|
||||||
|
final App app = Data.appData.apps().get(selectionModel.getMinSelectionIndex());
|
||||||
|
app.appArguments().forEach(arg -> this.appArgumentsTableModel.addRow(new Object[] { arg }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.scrollPane.setViewportView(this.list);
|
||||||
|
{
|
||||||
|
this.scrollPane_2 = new JScrollPane();
|
||||||
|
this.splitPane_1.setRightComponent(this.scrollPane_2);
|
||||||
|
{
|
||||||
|
this.appArgumentsTableModel.addColumn("Arguments");
|
||||||
|
|
||||||
|
this.table = new JTable(this.appArgumentsTableModel);
|
||||||
|
this.table.setRowSelectionAllowed(false);
|
||||||
|
this.table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||||
|
this.table.getColumnModel().getColumn(0).setCellRenderer(new AppArgumentsJCheckBoxRenderer(this.appArgumentsTableModel));
|
||||||
|
this.table.getColumnModel().getColumn(0).setCellEditor(new AppArgumentsJCheckBoxEditor());
|
||||||
|
|
||||||
|
this.scrollPane_2.setViewportView(this.table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.splitPane_2 = new JSplitPane();
|
||||||
|
this.splitPane_2.setResizeWeight(0.75);
|
||||||
|
this.splitPane.setRightComponent(this.splitPane_2);
|
||||||
|
|
||||||
|
this.scrollPane_1 = new JScrollPane();
|
||||||
|
this.splitPane_2.setLeftComponent(this.scrollPane_1);
|
||||||
|
this.list1Model = new DefaultListModel<>();
|
||||||
|
this.list_1 = new JList(this.list1Model);
|
||||||
|
this.list_1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
this.list_1.getSelectionModel().addListSelectionListener(e -> {
|
||||||
|
if (!e.getValueIsAdjusting()) {
|
||||||
|
final DefaultListSelectionModel selectionModel = (DefaultListSelectionModel) e.getSource();
|
||||||
|
if (selectionModel.getMinSelectionIndex() > -1) {
|
||||||
|
final Model model = Data.modelData.models().get(selectionModel.getMinSelectionIndex());
|
||||||
|
|
||||||
|
this.slider_context.setMaximum(model.maxContextSize());
|
||||||
|
this.slider_context.setMajorTickSpacing(model.maxContextSize() / 4);
|
||||||
|
this.slider_context.setMinorTickSpacing(model.maxContextSize() / 8);
|
||||||
|
this.slider_context.setValue(model.contextSize());
|
||||||
|
this.slider_context.setLabelTable(this.slider_context.createStandardLabels(model.maxContextSize() / 4));
|
||||||
|
this.slider_context.setSnapToTicks(true);
|
||||||
|
this.slider_context.repaint();
|
||||||
|
|
||||||
|
this.slider_threads.setValue(model.threads());
|
||||||
|
|
||||||
|
this.slider_gpu.setValue(model.gpuLayers());
|
||||||
|
|
||||||
|
this.lblPromptTemplate_1.setText(model.promptTemplate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.scrollPane_1.setViewportView(this.list_1);
|
||||||
|
{
|
||||||
|
this.panel_3 = new JPanel();
|
||||||
|
this.splitPane_2.setRightComponent(this.panel_3);
|
||||||
|
this.panel_3.setLayout(new GridLayout(0, 1, 0, 0));
|
||||||
|
{
|
||||||
|
this.lblContextLength = new JLabel("Context Length");
|
||||||
|
this.lblContextLength.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
this.panel_3.add(this.lblContextLength);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.slider_context = new JSlider();
|
||||||
|
this.slider_context.setValue(0);
|
||||||
|
this.slider_context.setMaximum(131072);
|
||||||
|
this.slider_context.setMajorTickSpacing(65536);
|
||||||
|
this.slider_context.setMinorTickSpacing(8192);
|
||||||
|
this.slider_context.setSnapToTicks(true);
|
||||||
|
this.slider_context.setPaintLabels(true);
|
||||||
|
this.slider_context.setPaintTicks(true);
|
||||||
|
this.panel_3.add(this.slider_context);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblThreads = new JLabel("Threads");
|
||||||
|
this.lblThreads.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
this.panel_3.add(this.lblThreads);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.slider_threads = new JSlider();
|
||||||
|
this.slider_threads.setSnapToTicks(true);
|
||||||
|
this.slider_threads.setValue(0);
|
||||||
|
this.slider_threads.setPaintLabels(true);
|
||||||
|
this.slider_threads.setPaintTicks(true);
|
||||||
|
this.slider_threads.setMajorTickSpacing(8);
|
||||||
|
this.slider_threads.setMinorTickSpacing(2);
|
||||||
|
this.slider_threads.setMaximum(24);
|
||||||
|
this.panel_3.add(this.slider_threads);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblGpuLayers = new JLabel("GPU Layers");
|
||||||
|
this.lblGpuLayers.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
this.panel_3.add(this.lblGpuLayers);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.slider_gpu = new JSlider();
|
||||||
|
this.slider_gpu.setPaintLabels(true);
|
||||||
|
this.slider_gpu.setMajorTickSpacing(16);
|
||||||
|
this.slider_gpu.setMinorTickSpacing(4);
|
||||||
|
this.slider_gpu.setValue(100);
|
||||||
|
this.slider_gpu.setPaintTicks(true);
|
||||||
|
this.panel_3.add(this.slider_gpu);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblPromptTemplate = new JLabel("Prompt Template");
|
||||||
|
this.panel_3.add(this.lblPromptTemplate);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblPromptTemplate_1 = new JLabel("-");
|
||||||
|
this.lblPromptTemplate_1.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
this.panel_3.add(this.lblPromptTemplate_1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.verticalStrut = Box.createVerticalStrut(20);
|
||||||
|
this.panel_3.add(this.verticalStrut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.panel_2 = new JPanel();
|
||||||
|
this.contentPane.add(this.panel_2, BorderLayout.NORTH);
|
||||||
|
{
|
||||||
|
this.btnAdd_1 = new JButton("Add");
|
||||||
|
this.btnAdd_1.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
JFileChooser fileChooser = new JFileChooser();
|
||||||
|
fileChooser.setDialogTitle("Select executable");
|
||||||
|
fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||||
|
if (fileChooser.showOpenDialog(LaunchFrame.this) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
final Path executable = fileChooser.getSelectedFile().toPath();
|
||||||
|
|
||||||
|
Path interpreter = null;
|
||||||
|
fileChooser = new JFileChooser();
|
||||||
|
fileChooser.setDialogTitle("Select interpreter or hit cancel if you don't need it");
|
||||||
|
fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||||
|
if (fileChooser.showOpenDialog(LaunchFrame.this) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
interpreter = fileChooser.getSelectedFile().toPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
final App app = new App(executable, interpreter, new ArrayList<>(), new ArrayList<>());
|
||||||
|
|
||||||
|
final AppPropertiesDialog appPropertiesDialog = new AppPropertiesDialog(LaunchFrame.this, app, () -> {
|
||||||
|
Data.saveApps();
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
});
|
||||||
|
appPropertiesDialog.setLocationRelativeTo(LaunchFrame.this);
|
||||||
|
appPropertiesDialog.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel_2.add(this.btnAdd_1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnEdit_1 = new JButton("Edit");
|
||||||
|
this.btnEdit_1.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select an app first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final App app = Data.appData.apps().get(index);
|
||||||
|
|
||||||
|
final AppPropertiesDialog appPropertiesDialog = new AppPropertiesDialog(LaunchFrame.this, app, () -> {
|
||||||
|
Data.saveApps();
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
});
|
||||||
|
appPropertiesDialog.setLocationRelativeTo(LaunchFrame.this);
|
||||||
|
appPropertiesDialog.setVisible(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel_2.add(this.btnEdit_1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnDelete_1 = new JButton("Delete");
|
||||||
|
this.btnDelete_1.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select an app first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Data.appData.apps().remove(index);
|
||||||
|
Data.saveApps();
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel_2.add(this.btnDelete_1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnClone_1 = new JButton("Clone");
|
||||||
|
this.btnClone_1.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int index = LaunchFrame.this.list.getSelectedIndex();
|
||||||
|
if (index == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select an app first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final App app = Data.appData.apps().get(index);
|
||||||
|
Data.appData.apps().add(index, new App(app.path(), app.interpreter(), new ArrayList<>(app.arguments()), new ArrayList<>(app.appArguments())));
|
||||||
|
|
||||||
|
Data.saveApps();
|
||||||
|
LaunchFrame.this.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel_2.add(this.btnClone_1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.horizontalStrut = Box.createHorizontalStrut(20);
|
||||||
|
this.panel_2.add(this.horizontalStrut);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.btnRun_1 = new JButton("Run");
|
||||||
|
this.btnRun_1.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
final int AppIndex = LaunchFrame.this.list.getSelectedIndex();
|
||||||
|
if (AppIndex == -1) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Select an app first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final App app = Data.appData.apps().get(AppIndex);
|
||||||
|
|
||||||
|
Model model = null;
|
||||||
|
final int modelIndex = LaunchFrame.this.list_1.getSelectedIndex();
|
||||||
|
if (modelIndex > -1) {
|
||||||
|
final Model template = Data.modelData.models().get(modelIndex);
|
||||||
|
model = new Model(
|
||||||
|
template.path(),
|
||||||
|
LaunchFrame.this.slider_context.getValue(),
|
||||||
|
template.maxContextSize(),
|
||||||
|
LaunchFrame.this.slider_gpu.getValue(),
|
||||||
|
LaunchFrame.this.slider_threads.getValue(),
|
||||||
|
template.promptTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<AppArgument> argumentOverrides = new ArrayList<>();
|
||||||
|
if (LaunchFrame.this.table.getCellEditor() != null) {
|
||||||
|
LaunchFrame.this.table.getCellEditor().stopCellEditing();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < LaunchFrame.this.appArgumentsTableModel.getRowCount(); i++) {
|
||||||
|
final AppArgument appArgument = (AppArgument) LaunchFrame.this.appArgumentsTableModel.getValueAt(i, 0);
|
||||||
|
if (appArgument.optional()) {
|
||||||
|
argumentOverrides.add(appArgument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
app.run(model, argumentOverrides);
|
||||||
|
}
|
||||||
|
catch (final IllegalArgumentException iae) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, iae.getMessage(), "Error Message", JOptionPane.WARNING_MESSAGE);
|
||||||
|
}
|
||||||
|
catch (final IOException ioa) {
|
||||||
|
JOptionPane.showMessageDialog(LaunchFrame.this, "Error: Could not execute program\n" + ioa.getMessage(), "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.panel_2.add(this.btnRun_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pack();
|
||||||
|
this.repaint();
|
||||||
|
this.splitPane.setDividerLocation(0.33);
|
||||||
|
this.splitPane_1.setDividerLocation(0.66);
|
||||||
|
this.splitPane_2.setDividerLocation(0.66);
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh() {
|
||||||
|
this.listModel.clear();
|
||||||
|
Data.appData.apps()
|
||||||
|
.stream()
|
||||||
|
.map(app -> app.path().getFileName() + " " + app.path().getParent() + " " + app.interpreter())
|
||||||
|
.forEach(this.listModel::addElement);
|
||||||
|
|
||||||
|
this.list1Model.clear();
|
||||||
|
Data.modelData.models()
|
||||||
|
.stream()
|
||||||
|
.map(model -> Path.of(model.path()).getFileName() + "; ctx " + model.contextSize() + "/" + model.maxContextSize())
|
||||||
|
.forEach(this.list1Model::addElement);
|
||||||
|
|
||||||
|
if (this.table.getCellEditor() != null) {
|
||||||
|
this.table.getCellEditor().stopCellEditing();
|
||||||
|
}
|
||||||
|
this.appArgumentsTableModel.setRowCount(0);
|
||||||
|
|
||||||
|
this.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AppArgumentsJCheckBoxRenderer extends JCheckBox implements TableCellRenderer {
|
||||||
|
|
||||||
|
private final DefaultTableModel model;
|
||||||
|
|
||||||
|
public AppArgumentsJCheckBoxRenderer(final DefaultTableModel model) {
|
||||||
|
super();
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
|
||||||
|
this.setText(((AppArgument) value).argument());
|
||||||
|
this.setSelected(((AppArgument) value).optional() ? ((AppArgument) value).default_() : true);
|
||||||
|
this.setEnabled(this.model.isCellEditable(row, column));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AppArgumentsJCheckBoxEditor extends AbstractCellEditor implements TableCellEditor {
|
||||||
|
|
||||||
|
private final JCheckBox checkBox = new JCheckBox();
|
||||||
|
|
||||||
|
private AppArgument appArgument;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {
|
||||||
|
this.appArgument = (AppArgument) value;
|
||||||
|
this.checkBox.setText(this.appArgument.argument());
|
||||||
|
this.checkBox.setSelected(this.appArgument.optional() ? this.appArgument.default_() : true);
|
||||||
|
return this.checkBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCellEditorValue() {
|
||||||
|
return new AppArgument(this.appArgument.argument(), this.appArgument.optional(), this.checkBox.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/de/extio/lm_launcher/Main.java
Normal file
25
src/de/extio/lm_launcher/Main.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||||
|
System.setProperty("swing.aatext", "true");
|
||||||
|
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
final LaunchFrame frame = new LaunchFrame();
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
catch (final Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/de/extio/lm_launcher/Model.java
Normal file
4
src/de/extio/lm_launcher/Model.java
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
record Model(String path, int contextSize, int maxContextSize, int gpuLayers, int threads, String promptTemplate) {
|
||||||
|
}
|
||||||
155
src/de/extio/lm_launcher/ModelPropertiesDialog.java
Normal file
155
src/de/extio/lm_launcher/ModelPropertiesDialog.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Frame;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.WindowConstants;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
public class ModelPropertiesDialog extends JDialog {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JPanel contentPanel = new JPanel();
|
||||||
|
|
||||||
|
JLabel lblName;
|
||||||
|
|
||||||
|
JLabel lblModelname;
|
||||||
|
|
||||||
|
JLabel lblMaxContextLength;
|
||||||
|
|
||||||
|
JTextField textField;
|
||||||
|
|
||||||
|
JLabel lblGpuLayers;
|
||||||
|
|
||||||
|
JTextField textField_1;
|
||||||
|
|
||||||
|
JLabel lblThreads;
|
||||||
|
|
||||||
|
JTextField textField_2;
|
||||||
|
JLabel lblContextLength;
|
||||||
|
JTextField textField_3;
|
||||||
|
JLabel lblPromptTemplate;
|
||||||
|
JTextField txtPrompttemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the dialog.
|
||||||
|
*/
|
||||||
|
public ModelPropertiesDialog(final Frame parent, final String modelPath, final Model editModel, final Consumer<Model> modelConsumer) {
|
||||||
|
super(parent);
|
||||||
|
this.setTitle("Model properties");
|
||||||
|
this.setModalityType(ModalityType.APPLICATION_MODAL);
|
||||||
|
this.setModal(true);
|
||||||
|
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
|
||||||
|
this.setBounds(100, 100, 678, 191);
|
||||||
|
this.getContentPane().setLayout(new BorderLayout());
|
||||||
|
this.contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
this.getContentPane().add(this.contentPanel, BorderLayout.CENTER);
|
||||||
|
this.contentPanel.setLayout(new GridLayout(0, 2, 0, 0));
|
||||||
|
{
|
||||||
|
this.lblName = new JLabel("Name");
|
||||||
|
this.contentPanel.add(this.lblName);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblModelname = new JLabel("ModelName");
|
||||||
|
this.contentPanel.add(this.lblModelname);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblContextLength = new JLabel("Context Length");
|
||||||
|
contentPanel.add(this.lblContextLength);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.textField_3 = new JTextField();
|
||||||
|
this.textField_3.setText("16000");
|
||||||
|
contentPanel.add(this.textField_3);
|
||||||
|
this.textField_3.setColumns(10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblMaxContextLength = new JLabel("Max Context Length");
|
||||||
|
this.contentPanel.add(this.lblMaxContextLength);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.textField = new JTextField();
|
||||||
|
this.textField.setText("128000");
|
||||||
|
this.contentPanel.add(this.textField);
|
||||||
|
this.textField.setColumns(10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblThreads = new JLabel("Threads");
|
||||||
|
this.contentPanel.add(this.lblThreads);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.textField_2 = new JTextField();
|
||||||
|
this.textField_2.setText("8");
|
||||||
|
this.contentPanel.add(this.textField_2);
|
||||||
|
this.textField_2.setColumns(10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.lblGpuLayers = new JLabel("GPU Layers");
|
||||||
|
this.contentPanel.add(this.lblGpuLayers);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.textField_1 = new JTextField();
|
||||||
|
this.textField_1.setText("99");
|
||||||
|
this.contentPanel.add(this.textField_1);
|
||||||
|
this.textField_1.setColumns(10);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final JPanel buttonPane = new JPanel();
|
||||||
|
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
this.getContentPane().add(buttonPane, BorderLayout.SOUTH);
|
||||||
|
{
|
||||||
|
final JButton okButton = new JButton("OK");
|
||||||
|
okButton.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
ModelPropertiesDialog.this.setVisible(false);
|
||||||
|
modelConsumer.accept(
|
||||||
|
new Model(modelPath,
|
||||||
|
Integer.parseInt(ModelPropertiesDialog.this.textField_3.getText()),
|
||||||
|
Integer.parseInt(ModelPropertiesDialog.this.textField.getText()),
|
||||||
|
Integer.parseInt(ModelPropertiesDialog.this.textField_1.getText()),
|
||||||
|
Integer.parseInt(ModelPropertiesDialog.this.textField_2.getText()),
|
||||||
|
ModelPropertiesDialog.this.txtPrompttemplate.getText()));
|
||||||
|
ModelPropertiesDialog.this.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
okButton.setActionCommand("OK");
|
||||||
|
buttonPane.add(okButton);
|
||||||
|
this.getRootPane().setDefaultButton(okButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lblModelname.setText(Path.of(modelPath).getFileName().toString());
|
||||||
|
{
|
||||||
|
this.lblPromptTemplate = new JLabel("Prompt Template");
|
||||||
|
contentPanel.add(this.lblPromptTemplate);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.txtPrompttemplate = new JTextField();
|
||||||
|
contentPanel.add(this.txtPrompttemplate);
|
||||||
|
this.txtPrompttemplate.setColumns(10);
|
||||||
|
}
|
||||||
|
if (editModel != null) {
|
||||||
|
this.textField.setText(String.valueOf(editModel.maxContextSize()));
|
||||||
|
this.textField_1.setText(String.valueOf(editModel.gpuLayers()));
|
||||||
|
this.textField_2.setText(String.valueOf(editModel.threads()));
|
||||||
|
this.textField_3.setText(String.valueOf(editModel.contextSize()));
|
||||||
|
this.txtPrompttemplate.setText(editModel.promptTemplate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
src/de/extio/lm_launcher/SelectModelDialog.java
Normal file
101
src/de/extio/lm_launcher/SelectModelDialog.java
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package de.extio.lm_launcher;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Frame;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.WindowConstants;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
public class SelectModelDialog extends JDialog {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final JPanel contentPanel = new JPanel();
|
||||||
|
|
||||||
|
JScrollPane scrollPane;
|
||||||
|
|
||||||
|
JList list;
|
||||||
|
|
||||||
|
DefaultListModel<String> listModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the dialog.
|
||||||
|
*/
|
||||||
|
public SelectModelDialog(final Frame parent, final Consumer<String> modelPathConsumer) {
|
||||||
|
super(parent);
|
||||||
|
this.setTitle("Select Model");
|
||||||
|
this.setModalityType(ModalityType.APPLICATION_MODAL);
|
||||||
|
this.setModal(true);
|
||||||
|
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
|
||||||
|
this.setBounds(100, 100, 578, 251);
|
||||||
|
this.getContentPane().setLayout(new BorderLayout());
|
||||||
|
this.contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
this.getContentPane().add(this.contentPanel, BorderLayout.CENTER);
|
||||||
|
this.contentPanel.setLayout(new BorderLayout(0, 0));
|
||||||
|
{
|
||||||
|
this.scrollPane = new JScrollPane();
|
||||||
|
this.contentPanel.add(this.scrollPane, BorderLayout.CENTER);
|
||||||
|
{
|
||||||
|
this.listModel = new DefaultListModel<>();
|
||||||
|
this.list = new JList(this.listModel);
|
||||||
|
this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
this.scrollPane.setViewportView(this.list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final JPanel buttonPane = new JPanel();
|
||||||
|
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
this.getContentPane().add(buttonPane, BorderLayout.SOUTH);
|
||||||
|
{
|
||||||
|
final JButton okButton = new JButton("OK");
|
||||||
|
okButton.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
if (SelectModelDialog.this.list.getSelectedIndex() == -1) {
|
||||||
|
JOptionPane.showMessageDialog(null, "Error: Select a model first", "Error Message", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SelectModelDialog.this.setVisible(false);
|
||||||
|
modelPathConsumer.accept(SelectModelDialog.this.listModel.getElementAt(SelectModelDialog.this.list.getSelectedIndex()));
|
||||||
|
SelectModelDialog.this.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
okButton.setActionCommand("OK");
|
||||||
|
buttonPane.add(okButton);
|
||||||
|
this.getRootPane().setDefaultButton(okButton);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
final JButton cancelButton = new JButton("Cancel");
|
||||||
|
cancelButton.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
SelectModelDialog.this.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cancelButton.setActionCommand("Cancel");
|
||||||
|
buttonPane.add(cancelButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
Data.scanModels().forEach(this.listModel::addElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user