Enhance model management: add temperature, top-p, top-k, and min-p settings with UI sliders

This commit is contained in:
extio-de
2026-05-29 21:36:43 +02:00
parent 0267aa34cd
commit f05611ebb4
8 changed files with 440 additions and 40 deletions

View File

@@ -1,20 +1,73 @@
# lm-launcher # lm-launcher
**Program Name:** Machine Learning Model and Application Manager A small Swing GUI for managing local GGUF models and launching apps with model-dependent command-line placeholders.
**Purpose:** The program is a graphical user interface (GUI) application that allows users to manage machine learning models and applications. It provides a user-friendly interface for adding, editing, deleting, and cloning models and applications, as well as running applications with selected models. ## What it does
**Key Features:** - scans a configured models directory for `.gguf` files
- stores per-model settings in `models.json`
- stores app launch definitions in `apps.json`
- launches apps with placeholders resolved from the selected model
1. **Model Management:** Users can add, edit, delete, and clone models, as well as view their properties. ## Model settings
2. **Application Management:** Users can add, edit, delete, and clone applications, as well as view their properties and run them with a selected model.
3. **Data Storage:** The program uses a data storage system that loads and manages data from two JSON files: "models.json" and "apps.json".
4. **GUI Components:** The program uses various GUI components, such as buttons, labels, sliders, and tables, to provide a user-friendly interface.
5. **Event Handling:** The program uses event listeners to handle user interactions, such as button clicks and table selections.
6. **Data Refresh:** The program has a method called `refresh()` that updates the GUI components with the latest data from the data storage.
7. **Model and Application Editing:** Users can edit the properties of models and applications using dedicated dialog windows.
8. **Argument Management:** Users can add, edit, or remove rows in a table to manage application arguments, and the changes are reflected in the application's arguments.
**Overall:** The program provides a comprehensive GUI application for managing machine learning models and applications, making it easier for users to work with these components and run applications with selected models. Each model can store:
*[requests=10, requestDuration=PT25.84142404S, inTokens=10623, outTokens=1240, tps=49.6]* - context length
- max context length
- threads
- GPU layers
- prompt template
- temperature
- top-p
- top-k
- min-p
The main window also provides sliders for quickly adjusting launch-time values for:
- context length
- threads
- GPU layers
- temperature
- top-p
- top-k
- min-p
## App placeholders
Use these tokens in app arguments:
- `MODEL`
- `CONTEXT_SIZE`
- `THREADS`
- `GPU_LAYERS`
- `TEMP`
- `TOP_P`
- `TOP_K`
- `MIN_P`
Example:
```text
-m MODEL -c CONTEXT_SIZE -t THREADS -ngl GPU_LAYERS --temp TEMP --top-p TOP_P --top-k TOP_K --min-p MIN_P
```
## Files
- `lm-launcher.properties` – launcher configuration
- `models.json` – saved model settings
- `apps.json` – saved app definitions
- `run.sh` – starts the packaged launcher jar
## Run
```bash
./run.sh
```
To build from source with the bundled Jackson jars:
```bash
javac -cp jackson-annotations-2.17.2.jar:jackson-core-2.17.2.jar:jackson-databind-2.17.2.jar -d /tmp/lm-launcher-build $(find src -name '*.java' | sort)
java -cp /tmp/lm-launcher-build:jackson-annotations-2.17.2.jar:jackson-core-2.17.2.jar:jackson-databind-2.17.2.jar de.extio.lm_launcher.Main
```

View File

@@ -1 +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":[]}]} {"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":[]},{"path":"file:///home/sb/lm/ollama-oai-bridge/start.sh","interpreter":null,"arguments":[],"appArguments":[]}]}

Binary file not shown.

View File

@@ -15,7 +15,11 @@ record App(Path path, Path interpreter, @Deprecated List<String> arguments, List
"MODEL", m -> m.path(), "MODEL", m -> m.path(),
"CONTEXT_SIZE", m -> String.valueOf(m.contextSize()), "CONTEXT_SIZE", m -> String.valueOf(m.contextSize()),
"THREADS", m -> String.valueOf(m.threads()), "THREADS", m -> String.valueOf(m.threads()),
"GPU_LAYERS", m -> String.valueOf(m.gpuLayers())); "GPU_LAYERS", m -> String.valueOf(m.gpuLayers()),
"TEMP", Model::temperatureDisplay,
"TOP_P", Model::topPDisplay,
"TOP_K", Model::topKDisplay,
"MIN_P", Model::minPDisplay);
String argumentsToString(boolean showAll) { String argumentsToString(boolean showAll) {
return this.argumentsToStringByArgs(this.appArguments.stream(), showAll); return this.argumentsToStringByArgs(this.appArguments.stream(), showAll);

View File

@@ -10,7 +10,6 @@ import java.nio.file.attribute.FileTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@@ -46,8 +45,10 @@ public class Data {
// Migration // Migration
for (int i = 0; i < modelData.models().size(); i++) { for (int i = 0; i < modelData.models().size(); i++) {
final Model model = modelData.models.get(i); final Model model = modelData.models.get(i);
if (model.maxContextSize() < model.contextSize() || model.promptTemplate() == null) { if (model.maxContextSize() < model.contextSize() || model.promptTemplate() == null || model.temperature() == null || model.topP() == null || model.topK() == null
modelData.models.set(i, new Model(model.path(), model.contextSize(), model.contextSize(), model.gpuLayers(), model.threads(), Objects.requireNonNullElse(model.promptTemplate(), ""), model.ctime())); || model.minP() == null) {
modelData.models.set(i, new Model(model.path(), model.contextSize(), model.maxContextSize(), model.gpuLayers(), model.threads(), model.temperature(), model.topP(), model.topK(),
model.minP(), model.promptTemplate(), model.ctime()));
} }
} }
sortModels(); sortModels();
@@ -154,7 +155,7 @@ public class Data {
catch (final IOException e) { catch (final IOException e) {
// Use 0 as fallback // Use 0 as fallback
} }
return new Model(path, 16000, 128000, 99, 6, "", ctime); return new Model(path, 16000, 128000, 99, 6, Model.DEFAULT_TEMPERATURE, Model.DEFAULT_TOP_P, Model.DEFAULT_TOP_K, Model.DEFAULT_MIN_P, "", ctime);
} }
static record ModelData(List<Model> models) { static record ModelData(List<Model> models) {

View File

@@ -11,6 +11,7 @@ import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -32,6 +33,7 @@ import javax.swing.JSplitPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.WindowConstants; import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
@@ -48,6 +50,8 @@ public class LaunchFrame extends JFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final int DECIMAL_SLIDER_SCALE = 100;
private final JPanel contentPane; private final JPanel contentPane;
JPanel panel; JPanel panel;
@@ -125,6 +129,30 @@ public class LaunchFrame extends JFrame {
JLabel lblPromptTemplate_1; JLabel lblPromptTemplate_1;
JLabel lblTemperature;
JSlider slider_temperature;
JLabel lblTemperatureValue;
JLabel lblTopP;
JSlider slider_topP;
JLabel lblTopPValue;
JLabel lblTopK;
JSlider slider_topK;
JLabel lblTopKValue;
JLabel lblMinP;
JSlider slider_minP;
JLabel lblMinPValue;
/** /**
* Create the frame. * Create the frame.
*/ */
@@ -255,8 +283,12 @@ public class LaunchFrame extends JFrame {
this.scrollPane_1.setViewportView(this.modelTree); this.scrollPane_1.setViewportView(this.modelTree);
{ {
final JScrollPane modelSettingsScrollPane = new JScrollPane();
modelSettingsScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
modelSettingsScrollPane.getVerticalScrollBar().setUnitIncrement(UIScaler.scale(16));
this.splitPane_2.setRightComponent(modelSettingsScrollPane);
this.panel_3 = new JPanel(); this.panel_3 = new JPanel();
this.splitPane_2.setRightComponent(this.panel_3); modelSettingsScrollPane.setViewportView(this.panel_3);
this.panel_3.setLayout(new GridLayout(0, 1, 0, 0)); this.panel_3.setLayout(new GridLayout(0, 1, 0, 0));
{ {
this.lblContextLength = new JLabel("Context Length"); this.lblContextLength = new JLabel("Context Length");
@@ -306,6 +338,7 @@ public class LaunchFrame extends JFrame {
} }
{ {
this.lblPromptTemplate = new JLabel("Prompt Template"); this.lblPromptTemplate = new JLabel("Prompt Template");
this.lblPromptTemplate.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblPromptTemplate); this.panel_3.add(this.lblPromptTemplate);
} }
{ {
@@ -313,6 +346,98 @@ public class LaunchFrame extends JFrame {
this.lblPromptTemplate_1.setHorizontalAlignment(SwingConstants.CENTER); this.lblPromptTemplate_1.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblPromptTemplate_1); this.panel_3.add(this.lblPromptTemplate_1);
} }
{
this.lblTemperature = new JLabel("Temperature");
this.lblTemperature.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTemperature);
}
{
this.slider_temperature = new JSlider();
this.slider_temperature.setMinimum((int) (Model.MIN_TEMPERATURE * DECIMAL_SLIDER_SCALE));
this.slider_temperature.setMaximum((int) (Model.MAX_TEMPERATURE * DECIMAL_SLIDER_SCALE));
this.slider_temperature.setValue(LaunchFrame.doubleToSlider(Model.DEFAULT_TEMPERATURE));
this.slider_temperature.setMajorTickSpacing(50);
this.slider_temperature.setMinorTickSpacing(5);
this.slider_temperature.setLabelTable(LaunchFrame.createDecimalLabelTable(new int[] { 0, 50, 100, 150, 200 }));
this.slider_temperature.setPaintLabels(true);
this.slider_temperature.setPaintTicks(true);
this.slider_temperature.addChangeListener(e -> LaunchFrame.this.updateSamplingValueLabels());
this.panel_3.add(this.slider_temperature);
}
{
this.lblTemperatureValue = new JLabel("-");
this.lblTemperatureValue.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTemperatureValue);
}
{
this.lblTopP = new JLabel("Top P");
this.lblTopP.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTopP);
}
{
this.slider_topP = new JSlider();
this.slider_topP.setMinimum((int) (Model.MIN_TOP_P * DECIMAL_SLIDER_SCALE));
this.slider_topP.setMaximum((int) (Model.MAX_TOP_P * DECIMAL_SLIDER_SCALE));
this.slider_topP.setValue(LaunchFrame.doubleToSlider(Model.DEFAULT_TOP_P));
this.slider_topP.setMajorTickSpacing(25);
this.slider_topP.setMinorTickSpacing(5);
this.slider_topP.setLabelTable(LaunchFrame.createDecimalLabelTable(new int[] { 0, 25, 50, 75, 100 }));
this.slider_topP.setPaintLabels(true);
this.slider_topP.setPaintTicks(true);
this.slider_topP.addChangeListener(e -> LaunchFrame.this.updateSamplingValueLabels());
this.panel_3.add(this.slider_topP);
}
{
this.lblTopPValue = new JLabel("-");
this.lblTopPValue.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTopPValue);
}
{
this.lblTopK = new JLabel("Top K");
this.lblTopK.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTopK);
}
{
this.slider_topK = new JSlider();
this.slider_topK.setMinimum(Model.MIN_TOP_K);
this.slider_topK.setMaximum(Model.MAX_TOP_K);
this.slider_topK.setValue(Model.DEFAULT_TOP_K);
this.slider_topK.setMajorTickSpacing(100);
this.slider_topK.setMinorTickSpacing(25);
this.slider_topK.setSnapToTicks(true);
this.slider_topK.setPaintLabels(true);
this.slider_topK.setPaintTicks(true);
this.slider_topK.addChangeListener(e -> LaunchFrame.this.updateSamplingValueLabels());
this.panel_3.add(this.slider_topK);
}
{
this.lblTopKValue = new JLabel("-");
this.lblTopKValue.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblTopKValue);
}
{
this.lblMinP = new JLabel("Min P");
this.lblMinP.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblMinP);
}
{
this.slider_minP = new JSlider();
this.slider_minP.setMinimum((int) (Model.MIN_MIN_P * DECIMAL_SLIDER_SCALE));
this.slider_minP.setMaximum((int) (Model.MAX_MIN_P * DECIMAL_SLIDER_SCALE));
this.slider_minP.setValue(LaunchFrame.doubleToSlider(Model.DEFAULT_MIN_P));
this.slider_minP.setMajorTickSpacing(25);
this.slider_minP.setMinorTickSpacing(5);
this.slider_minP.setLabelTable(LaunchFrame.createDecimalLabelTable(new int[] { 0, 25, 50, 75, 100 }));
this.slider_minP.setPaintLabels(true);
this.slider_minP.setPaintTicks(true);
this.slider_minP.addChangeListener(e -> LaunchFrame.this.updateSamplingValueLabels());
this.panel_3.add(this.slider_minP);
}
{
this.lblMinPValue = new JLabel("-");
this.lblMinPValue.setHorizontalAlignment(SwingConstants.CENTER);
this.panel_3.add(this.lblMinPValue);
}
{ {
this.verticalStrut = Box.createVerticalStrut(20); this.verticalStrut = Box.createVerticalStrut(20);
this.panel_3.add(this.verticalStrut); this.panel_3.add(this.verticalStrut);
@@ -448,6 +573,10 @@ public class LaunchFrame extends JFrame {
template.maxContextSize(), template.maxContextSize(),
LaunchFrame.this.slider_gpu.getValue(), LaunchFrame.this.slider_gpu.getValue(),
LaunchFrame.this.slider_threads.getValue(), LaunchFrame.this.slider_threads.getValue(),
LaunchFrame.this.sliderValue(LaunchFrame.this.slider_temperature),
LaunchFrame.this.sliderValue(LaunchFrame.this.slider_topP),
LaunchFrame.this.slider_topK.getValue(),
LaunchFrame.this.sliderValue(LaunchFrame.this.slider_minP),
template.promptTemplate(), template.promptTemplate(),
template.ctime()); template.ctime());
} }
@@ -484,6 +613,7 @@ public class LaunchFrame extends JFrame {
UIScaler.scaleComponentFonts(this); UIScaler.scaleComponentFonts(this);
UIScaler.centerOnPrimaryDisplay(this); UIScaler.centerOnPrimaryDisplay(this);
this.updateSamplingValueLabels();
this.repaint(); this.repaint();
this.splitPane.setDividerLocation(0.33); this.splitPane.setDividerLocation(0.33);
this.splitPane_1.setDividerLocation(0.66); this.splitPane_1.setDividerLocation(0.66);
@@ -512,7 +642,35 @@ public class LaunchFrame extends JFrame {
this.slider_threads.setValue(model.threads()); this.slider_threads.setValue(model.threads());
this.slider_gpu.setValue(model.gpuLayers()); this.slider_gpu.setValue(model.gpuLayers());
this.slider_temperature.setValue(LaunchFrame.doubleToSlider(model.temperatureValue()));
this.slider_topP.setValue(LaunchFrame.doubleToSlider(model.topPValue()));
this.slider_topK.setValue(model.topKValue());
this.slider_minP.setValue(LaunchFrame.doubleToSlider(model.minPValue()));
this.lblPromptTemplate_1.setText(model.promptTemplate() != null && !model.promptTemplate().isEmpty() ? model.promptTemplate() : "-"); this.lblPromptTemplate_1.setText(model.promptTemplate() != null && !model.promptTemplate().isEmpty() ? model.promptTemplate() : "-");
this.updateSamplingValueLabels();
}
private void updateSamplingValueLabels() {
this.lblTemperatureValue.setText(Model.formatDecimal(this.sliderValue(this.slider_temperature)));
this.lblTopPValue.setText(Model.formatDecimal(this.sliderValue(this.slider_topP)));
this.lblTopKValue.setText(String.valueOf(this.slider_topK.getValue()));
this.lblMinPValue.setText(Model.formatDecimal(this.sliderValue(this.slider_minP)));
}
private double sliderValue(final JSlider slider) {
return slider.getValue() / (double) DECIMAL_SLIDER_SCALE;
}
private static int doubleToSlider(final double value) {
return (int) Math.round(value * DECIMAL_SLIDER_SCALE);
}
private static Hashtable<Integer, JLabel> createDecimalLabelTable(final int[] values) {
final Hashtable<Integer, JLabel> labels = new Hashtable<>();
for (final int value : values) {
labels.put(value, new JLabel(Model.formatDecimal(value / (double) DECIMAL_SLIDER_SCALE)));
}
return labels;
} }
private void refresh() { private void refresh() {

View File

@@ -1,4 +1,97 @@
package de.extio.lm_launcher; package de.extio.lm_launcher;
record Model(String path, int contextSize, int maxContextSize, int gpuLayers, int threads, String promptTemplate, long ctime) { import java.math.BigDecimal;
record Model(String path, int contextSize, int maxContextSize, int gpuLayers, int threads, Double temperature, Double topP,
Integer topK, Double minP, String promptTemplate, long ctime) {
static final double DEFAULT_TEMPERATURE = 0.8d;
static final double DEFAULT_TOP_P = 0.95d;
static final int DEFAULT_TOP_K = 40;
static final double DEFAULT_MIN_P = 0.05d;
static final double MIN_TEMPERATURE = 0d;
static final double MAX_TEMPERATURE = 2d;
static final double MIN_TOP_P = 0d;
static final double MAX_TOP_P = 1d;
static final int MIN_TOP_K = 0;
static final int MAX_TOP_K = 500;
static final double MIN_MIN_P = 0d;
static final double MAX_MIN_P = 1d;
public Model {
maxContextSize = Math.max(Math.max(1, maxContextSize), Math.max(1, contextSize));
contextSize = clampInt(contextSize, 1, maxContextSize);
gpuLayers = Math.max(0, gpuLayers);
threads = Math.max(0, threads);
temperature = sanitizeDouble(temperature, DEFAULT_TEMPERATURE, MIN_TEMPERATURE, MAX_TEMPERATURE);
topP = sanitizeDouble(topP, DEFAULT_TOP_P, MIN_TOP_P, MAX_TOP_P);
topK = sanitizeInt(topK, DEFAULT_TOP_K, MIN_TOP_K, MAX_TOP_K);
minP = sanitizeDouble(minP, DEFAULT_MIN_P, MIN_MIN_P, MAX_MIN_P);
promptTemplate = promptTemplate == null ? "" : promptTemplate;
}
double temperatureValue() {
return this.temperature;
}
double topPValue() {
return this.topP;
}
int topKValue() {
return this.topK;
}
double minPValue() {
return this.minP;
}
String temperatureDisplay() {
return formatDecimal(this.temperatureValue());
}
String topPDisplay() {
return formatDecimal(this.topPValue());
}
String topKDisplay() {
return String.valueOf(this.topKValue());
}
String minPDisplay() {
return formatDecimal(this.minPValue());
}
private static Double sanitizeDouble(final Double value, final double defaultValue, final double minValue, final double maxValue) {
if (value == null || value.isNaN() || value.isInfinite()) {
return defaultValue;
}
return Math.max(minValue, Math.min(maxValue, value));
}
private static Integer sanitizeInt(final Integer value, final int defaultValue, final int minValue, final int maxValue) {
if (value == null) {
return defaultValue;
}
return clampInt(value, minValue, maxValue);
}
private static int clampInt(final int value, final int minValue, final int maxValue) {
return Math.max(minValue, Math.min(maxValue, value));
}
static String formatDecimal(final double value) {
return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
}
} }

View File

@@ -12,6 +12,7 @@ import java.util.function.Consumer;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.WindowConstants; import javax.swing.WindowConstants;
@@ -42,18 +43,27 @@ public class ModelPropertiesDialog extends JDialog {
JTextField textField_3; JTextField textField_3;
JLabel lblPromptTemplate; JLabel lblPromptTemplate;
JTextField txtPrompttemplate; JTextField txtPrompttemplate;
JLabel lblTemperature;
JTextField txtTemperature;
JLabel lblTopP;
JTextField txtTopP;
JLabel lblTopK;
JTextField txtTopK;
JLabel lblMinP;
JTextField txtMinP;
/** /**
* Create the dialog. * Create the dialog.
*/ */
public ModelPropertiesDialog(final Frame parent, final String modelPath, final Model editModel, final Consumer<Model> modelConsumer) { public ModelPropertiesDialog(final Frame parent, final String modelPath, final Model editModel, final Consumer<Model> modelConsumer) {
super(parent); super(parent);
final Model modelToEdit = editModel != null ? editModel : Data.defaultModel(modelPath);
this.setTitle("Model properties"); this.setTitle("Model properties");
this.setModalityType(ModalityType.APPLICATION_MODAL); this.setModalityType(ModalityType.APPLICATION_MODAL);
this.setModal(true); this.setModal(true);
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
this.setBounds(UIScaler.scale(100), UIScaler.scale(100), UIScaler.scale(678), UIScaler.scale(191)); this.setBounds(UIScaler.scale(100), UIScaler.scale(100), UIScaler.scale(678), UIScaler.scale(320));
this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().setLayout(new BorderLayout());
this.contentPanel.setBorder(new EmptyBorder(UIScaler.scale(5), UIScaler.scale(5), UIScaler.scale(5), UIScaler.scale(5))); this.contentPanel.setBorder(new EmptyBorder(UIScaler.scale(5), UIScaler.scale(5), UIScaler.scale(5), UIScaler.scale(5)));
this.getContentPane().add(this.contentPanel, BorderLayout.CENTER); this.getContentPane().add(this.contentPanel, BorderLayout.CENTER);
@@ -106,6 +116,46 @@ public class ModelPropertiesDialog extends JDialog {
this.contentPanel.add(this.textField_1); this.contentPanel.add(this.textField_1);
this.textField_1.setColumns(10); this.textField_1.setColumns(10);
} }
{
this.lblTemperature = new JLabel("Temperature");
this.contentPanel.add(this.lblTemperature);
}
{
this.txtTemperature = new JTextField();
this.txtTemperature.setText(Model.formatDecimal(Model.DEFAULT_TEMPERATURE));
this.contentPanel.add(this.txtTemperature);
this.txtTemperature.setColumns(10);
}
{
this.lblTopP = new JLabel("Top P");
this.contentPanel.add(this.lblTopP);
}
{
this.txtTopP = new JTextField();
this.txtTopP.setText(Model.formatDecimal(Model.DEFAULT_TOP_P));
this.contentPanel.add(this.txtTopP);
this.txtTopP.setColumns(10);
}
{
this.lblTopK = new JLabel("Top K");
this.contentPanel.add(this.lblTopK);
}
{
this.txtTopK = new JTextField();
this.txtTopK.setText(String.valueOf(Model.DEFAULT_TOP_K));
this.contentPanel.add(this.txtTopK);
this.txtTopK.setColumns(10);
}
{
this.lblMinP = new JLabel("Min P");
this.contentPanel.add(this.lblMinP);
}
{
this.txtMinP = new JTextField();
this.txtMinP.setText(Model.formatDecimal(Model.DEFAULT_MIN_P));
this.contentPanel.add(this.txtMinP);
this.txtMinP.setColumns(10);
}
{ {
final JPanel buttonPane = new JPanel(); final JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
@@ -116,18 +166,31 @@ public class ModelPropertiesDialog extends JDialog {
@Override @Override
public void actionPerformed(final ActionEvent e) { public void actionPerformed(final ActionEvent e) {
try {
final int contextSize = ModelPropertiesDialog.clampInt(ModelPropertiesDialog.parseIntField(ModelPropertiesDialog.this.textField_3, "Context Length"), 1,
Integer.MAX_VALUE);
final int maxContextSize = ModelPropertiesDialog.clampInt(ModelPropertiesDialog.parseIntField(ModelPropertiesDialog.this.textField, "Max Context Length"), 1,
Integer.MAX_VALUE);
final int gpuLayers = Math.max(0, ModelPropertiesDialog.parseIntField(ModelPropertiesDialog.this.textField_1, "GPU Layers"));
final int threads = Math.max(0, ModelPropertiesDialog.parseIntField(ModelPropertiesDialog.this.textField_2, "Threads"));
final double temperature = ModelPropertiesDialog.clampDouble(ModelPropertiesDialog.parseDoubleField(ModelPropertiesDialog.this.txtTemperature, "Temperature"),
Model.MIN_TEMPERATURE, Model.MAX_TEMPERATURE);
final double topP = ModelPropertiesDialog.clampDouble(ModelPropertiesDialog.parseDoubleField(ModelPropertiesDialog.this.txtTopP, "Top P"), Model.MIN_TOP_P,
Model.MAX_TOP_P);
final int topK = ModelPropertiesDialog.clampInt(ModelPropertiesDialog.parseIntField(ModelPropertiesDialog.this.txtTopK, "Top K"), Model.MIN_TOP_K,
Model.MAX_TOP_K);
final double minP = ModelPropertiesDialog.clampDouble(ModelPropertiesDialog.parseDoubleField(ModelPropertiesDialog.this.txtMinP, "Min P"), Model.MIN_MIN_P,
Model.MAX_MIN_P);
ModelPropertiesDialog.this.setVisible(false); ModelPropertiesDialog.this.setVisible(false);
final Model modelToSave = editModel != null ? editModel : Data.defaultModel(modelPath);
modelConsumer.accept( modelConsumer.accept(
new Model(modelPath, new Model(modelPath, contextSize, maxContextSize, gpuLayers, threads, temperature, topP, topK, minP, ModelPropertiesDialog.this.txtPrompttemplate.getText(),
Integer.parseInt(ModelPropertiesDialog.this.textField_3.getText()), modelToEdit.ctime()));
Integer.parseInt(ModelPropertiesDialog.this.textField.getText()),
Integer.parseInt(ModelPropertiesDialog.this.textField_1.getText()),
Integer.parseInt(ModelPropertiesDialog.this.textField_2.getText()),
ModelPropertiesDialog.this.txtPrompttemplate.getText(),
modelToSave.ctime()));
ModelPropertiesDialog.this.dispose(); ModelPropertiesDialog.this.dispose();
} }
catch (final NumberFormatException nfe) {
JOptionPane.showMessageDialog(ModelPropertiesDialog.this, nfe.getMessage(), "Invalid model property", JOptionPane.WARNING_MESSAGE);
}
}
}); });
okButton.setActionCommand("OK"); okButton.setActionCommand("OK");
buttonPane.add(okButton); buttonPane.add(okButton);
@@ -145,16 +208,44 @@ public class ModelPropertiesDialog extends JDialog {
contentPanel.add(this.txtPrompttemplate); contentPanel.add(this.txtPrompttemplate);
this.txtPrompttemplate.setColumns(10); this.txtPrompttemplate.setColumns(10);
} }
if (editModel != null) { this.textField.setText(String.valueOf(modelToEdit.maxContextSize()));
this.textField.setText(String.valueOf(editModel.maxContextSize())); this.textField_1.setText(String.valueOf(modelToEdit.gpuLayers()));
this.textField_1.setText(String.valueOf(editModel.gpuLayers())); this.textField_2.setText(String.valueOf(modelToEdit.threads()));
this.textField_2.setText(String.valueOf(editModel.threads())); this.textField_3.setText(String.valueOf(modelToEdit.contextSize()));
this.textField_3.setText(String.valueOf(editModel.contextSize())); this.txtTemperature.setText(modelToEdit.temperatureDisplay());
this.txtPrompttemplate.setText(editModel.promptTemplate()); this.txtTopP.setText(modelToEdit.topPDisplay());
} this.txtTopK.setText(modelToEdit.topKDisplay());
this.txtMinP.setText(modelToEdit.minPDisplay());
this.txtPrompttemplate.setText(modelToEdit.promptTemplate());
// Apply font scaling to all components // Apply font scaling to all components
UIScaler.scaleComponentFonts(this); UIScaler.scaleComponentFonts(this);
} }
private static int parseIntField(final JTextField field, final String fieldName) {
try {
return Integer.parseInt(field.getText().trim());
}
catch (final NumberFormatException nfe) {
throw new NumberFormatException(fieldName + " must be a whole number.");
}
}
private static double parseDoubleField(final JTextField field, final String fieldName) {
try {
return Double.parseDouble(field.getText().trim());
}
catch (final NumberFormatException nfe) {
throw new NumberFormatException(fieldName + " must be a decimal number.");
}
}
private static int clampInt(final int value, final int minValue, final int maxValue) {
return Math.max(minValue, Math.min(maxValue, value));
}
private static double clampDouble(final double value, final double minValue, final double maxValue) {
return Math.max(minValue, Math.min(maxValue, value));
}
} }