diff --git a/config.properties b/config.properties
index c199559..92616c4 100644
--- a/config.properties
+++ b/config.properties
@@ -1,6 +1,6 @@
#Llama Runner Configuration
-#Thu Apr 02 10:20:00 CEST 2026
+#Tue Apr 14 16:53:17 CEST 2026
windowHeight=1189
-windowWidth=711
-windowX=1849
-windowY=211
+windowWidth=684
+windowX=1876
+windowY=210
diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index 7686dca..d8edc73 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -1,45 +1,45 @@
-
-
- 4.0.0
- cz.kamma
- llama-runner
- Llama Runner
- 1.0-SNAPSHOT
- GUI application for running llama-server with customizable parameters
-
-
-
- maven-compiler-plugin
- 3.11.0
-
- 11
- 11
-
-
-
- maven-shade-plugin
- 3.5.0
-
-
- package
-
- shade
-
-
-
-
- cz.kamma.llamarunner.Main
-
-
-
-
-
-
-
-
-
- 11
- 11
- UTF-8
-
-
+
+
+ 4.0.0
+ cz.kamma
+ llama-runner
+ Llama Runner
+ 1.0-SNAPSHOT
+ GUI application for running llama-server with customizable parameters
+
+
+
+ maven-compiler-plugin
+ 3.11.0
+
+ 11
+ 11
+
+
+
+ maven-shade-plugin
+ 3.5.0
+
+
+ package
+
+ shade
+
+
+
+
+ cz.kamma.llamarunner.Main
+
+
+
+
+
+
+
+
+
+ 11
+ 11
+ UTF-8
+
+
diff --git a/profiles.json b/profiles.json
index c6d8e87..9cd609d 100644
--- a/profiles.json
+++ b/profiles.json
@@ -29,8 +29,8 @@
"threads": 99,
"flashAttention": true,
"kvUnified": true,
- "cacheTypeK": "turbo3",
- "cacheTypeV": "turbo3",
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
"temperature": 0.6,
"topP": 0.95,
"topK": 20,
@@ -40,7 +40,7 @@
"modelPath": "/home/kamma/models/Qwen3.5-35B-A3B-Q6_K.gguf",
"chatTemplateKwargs": "{\"enable_thinking\": false}",
"ngl": 999,
- "fit": false,
+ "fit": true,
"reasoning": false
},
"QwenCoderNext-160k": {
@@ -249,8 +249,8 @@
"threads": 99,
"flashAttention": true,
"kvUnified": true,
- "cacheTypeK": "turbo4",
- "cacheTypeV": "turbo4",
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
"temperature": 0.6,
"topP": 0.95,
"topK": 20,
@@ -262,5 +262,93 @@
"ngl": 999,
"fit": true,
"reasoning": true
+ },
+ "Qwen35-35B-A3B-Q6K-Q8-256k": {
+ "host": "0.0.0.0",
+ "port": 3080,
+ "parallel": 1,
+ "batchSize": 2048,
+ "threads": 99,
+ "flashAttention": true,
+ "kvUnified": true,
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
+ "temperature": 0.6,
+ "topP": 0.95,
+ "topK": 20,
+ "minP": 0.0,
+ "ctxSize": 256000,
+ "enableThinking": false,
+ "modelPath": "/home/kamma/models/Qwen3.5-35B-A3B-Q6_K.gguf",
+ "chatTemplateKwargs": "",
+ "ngl": 999,
+ "fit": true,
+ "reasoning": true
+ },
+ "gemma-4-31B-it-UD-Q6KXL-54k": {
+ "host": "0.0.0.0",
+ "port": 3080,
+ "parallel": 1,
+ "batchSize": 2048,
+ "threads": 99,
+ "flashAttention": true,
+ "kvUnified": true,
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
+ "temperature": 0.9,
+ "topP": 0.95,
+ "topK": 20,
+ "minP": 0.0,
+ "ctxSize": 54000,
+ "enableThinking": false,
+ "modelPath": "/home/kamma/models/gemma-4-31B-it-UD-Q6_K_XL.gguf",
+ "chatTemplateKwargs": "",
+ "ngl": 99,
+ "fit": false,
+ "reasoning": true
+ },
+ "gemma-4-26B-A4B-it-UD-Q8KXL-180k": {
+ "host": "0.0.0.0",
+ "port": 3080,
+ "parallel": 1,
+ "batchSize": 2048,
+ "threads": 99,
+ "flashAttention": true,
+ "kvUnified": true,
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
+ "temperature": 0.9,
+ "topP": 0.95,
+ "topK": 20,
+ "minP": 0.0,
+ "ctxSize": 180000,
+ "enableThinking": false,
+ "modelPath": "/home/kamma/models/gemma-4-26B-A4B-it-UD-Q8_K_XL.gguf",
+ "chatTemplateKwargs": "",
+ "ngl": 99,
+ "fit": false,
+ "reasoning": true
+ },
+ "gemma-4-31B-it-Q6K-112k": {
+ "host": "0.0.0.0",
+ "port": 3080,
+ "parallel": 1,
+ "batchSize": 2048,
+ "threads": 99,
+ "flashAttention": true,
+ "kvUnified": true,
+ "cacheTypeK": "q8_0",
+ "cacheTypeV": "q8_0",
+ "temperature": 0.8,
+ "topP": 0.95,
+ "topK": 20,
+ "minP": 0.0,
+ "ctxSize": 112000,
+ "enableThinking": false,
+ "modelPath": "/home/kamma/models/gemma-4-31B-it-Q6_K.gguf",
+ "chatTemplateKwargs": "{\"enable_thinking\": true}",
+ "ngl": 99,
+ "fit": false,
+ "reasoning": true
}
}
\ No newline at end of file
diff --git a/src/main/java/cz/kamma/llamarunner/Main.java b/src/main/java/cz/kamma/llamarunner/Main.java
index 5adf54d..f923a1f 100644
--- a/src/main/java/cz/kamma/llamarunner/Main.java
+++ b/src/main/java/cz/kamma/llamarunner/Main.java
@@ -157,30 +157,46 @@ public class Main extends JFrame {
}
private JPanel createModelSelectionPanel() {
- JPanel panel = new JPanel(new BorderLayout(5, 5));
+ JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(Color.WHITE), "Model"));
- // Model selection row
- JPanel modelRow = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
- modelRow.add(new JLabel("Model:"));
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.insets = new Insets(5, 5, 5, 5);
+ gbc.anchor = GridBagConstraints.WEST;
+
+ // Label
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.weightx = 0;
+ gbc.fill = GridBagConstraints.NONE;
+ panel.add(new JLabel("Model:"), gbc);
+
+ // ComboBox
+ gbc.gridx = 1;
+ gbc.weightx = 1.0;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
modelComboBox = new JComboBox<>();
modelComboBox.setEditable(true);
- modelComboBox.setPreferredSize(new Dimension(300, 25));
+ modelComboBox.setMinimumSize(new Dimension(200, 25));
+ modelComboBox.setPreferredSize(new Dimension(500, 25));
modelComboBox.addActionListener(e -> updateCommandPreview());
- modelRow.add(modelComboBox);
+ panel.add(modelComboBox, gbc);
+ // Buttons panel
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
browseModelsButton = new JButton("Browse");
browseModelsButton.addActionListener(e -> browseModelsDir());
- modelRow.add(browseModelsButton);
+ buttonPanel.add(browseModelsButton);
refreshModelsButton = new JButton("Refresh");
refreshModelsButton.addActionListener(e -> loadModels());
- modelRow.add(refreshModelsButton);
+ buttonPanel.add(refreshModelsButton);
- JScrollPane scrollPane = new JScrollPane(modelRow);
- scrollPane.setBorder(null);
- panel.add(scrollPane, BorderLayout.CENTER);
+ gbc.gridx = 2;
+ gbc.weightx = 0;
+ gbc.fill = GridBagConstraints.NONE;
+ panel.add(buttonPanel, gbc);
return panel;
}
@@ -204,35 +220,35 @@ public class Main extends JFrame {
gbc.fill = GridBagConstraints.HORIZONTAL;
profileComboBox = new JComboBox<>();
profileComboBox.setEditable(true);
- profileComboBox.setMaximumSize(new Dimension(200, 25));
- profileComboBox.setPreferredSize(new Dimension(150, 25));
+ profileComboBox.setMinimumSize(new Dimension(200, 25));
+ profileComboBox.setPreferredSize(new Dimension(500, 25));
profileChangeListener = e -> profileComboBoxChanged();
profileComboBox.addActionListener(profileChangeListener);
panel.add(profileComboBox, gbc);
+ // Buttons container
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
+
+ saveProfileButton = new JButton("Save");
+ saveProfileButton.addActionListener(e -> showSaveProfileDialog());
+ buttonPanel.add(saveProfileButton);
+
+ JButton saveAsButton = new JButton("Save As...");
+ saveAsButton.addActionListener(e -> showSaveAsProfileDialog());
+ buttonPanel.add(saveAsButton);
+
+ deleteProfileButton = new JButton("Delete");
+ deleteProfileButton.addActionListener(e -> showDeleteProfileDialog());
+ buttonPanel.add(deleteProfileButton);
+
+ JButton renameButton = new JButton("Rename");
+ renameButton.addActionListener(e -> showRenameProfileDialog());
+ buttonPanel.add(renameButton);
+
gbc.gridx = 2;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
-
- gbc.gridx = 3;
- saveProfileButton = new JButton("Save");
- saveProfileButton.addActionListener(e -> showSaveProfileDialog());
- panel.add(saveProfileButton, gbc);
-
- gbc.gridx = 4;
- JButton saveAsButton = new JButton("Save As...");
- saveAsButton.addActionListener(e -> showSaveAsProfileDialog());
- panel.add(saveAsButton, gbc);
-
- gbc.gridx = 5;
- deleteProfileButton = new JButton("Delete");
- deleteProfileButton.addActionListener(e -> showDeleteProfileDialog());
- panel.add(deleteProfileButton, gbc);
-
- gbc.gridx = 6;
- JButton renameButton = new JButton("Rename");
- renameButton.addActionListener(e -> showRenameProfileDialog());
- panel.add(renameButton, gbc);
+ panel.add(buttonPanel, gbc);
return panel;
}
@@ -247,16 +263,26 @@ public class Main extends JFrame {
File[] modelFiles = modelsDir.listFiles((dir, name) -> name.endsWith(".gguf"));
if (modelFiles != null) {
List sortedFiles = new ArrayList<>(Arrays.asList(modelFiles));
- sortedFiles.sort((a, b) -> a.getName().compareTo(b.getName()));
+ sortedFiles.sort((a, b) -> a.getName().compareToIgnoreCase(b.getName()));
for (File file : sortedFiles) {
- modelComboBox.addItem(file.getName());
+ double sizeInGb = (double) file.length() / (1024 * 1024 * 1024);
+ String displayName = String.format("%s (%.2f GB)", file.getName(), sizeInGb);
+ modelComboBox.addItem(displayName);
}
}
}
- if (selectedItem != null && modelComboBox.getItemCount() > 0
- && !modelComboBox.getItemAt(0).equals(selectedItem)) {
- modelComboBox.addItem(selectedItem);
+ if (selectedItem != null && modelComboBox.getItemCount() > 0) {
+ boolean found = false;
+ for (int i = 0; i < modelComboBox.getItemCount(); i++) {
+ if (modelComboBox.getItemAt(i).equals(selectedItem)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ modelComboBox.addItem(selectedItem);
+ }
}
}
@@ -356,8 +382,16 @@ public class Main extends JFrame {
config.setTopK(Integer.parseInt(topKField.getText()));
config.setMinP(Double.parseDouble(minPField.getText()));
config.setCtxSize(Integer.parseInt(ctxSizeField.getText()));
- String modelName = (String) modelComboBox.getSelectedItem();
- config.setModelPath(modelName != null ? new File(modelsDirPath, modelName).getAbsolutePath() : "");
+ String displayName = (String) modelComboBox.getSelectedItem();
+ String fileName = "";
+ if (displayName != null) {
+ if (displayName.contains(" (") && displayName.endsWith(" GB)")) {
+ fileName = displayName.substring(0, displayName.lastIndexOf(" ("));
+ } else {
+ fileName = displayName;
+ }
+ }
+ config.setModelPath(fileName != null && !fileName.isEmpty() ? new File(modelsDirPath, fileName).getAbsolutePath() : "");
config.setChatTemplateKwargs(kwargsField.getText());
config.setNgl(Integer.parseInt(nglField.getText()));
return config;
@@ -391,6 +425,13 @@ public class Main extends JFrame {
String modelName = config.getModelPath() != null
? new File(config.getModelPath()).getName()
: "";
+ if (!modelName.isEmpty()) {
+ File modelFile = new File(modelsDirPath, modelName);
+ if (modelFile.exists()) {
+ double sizeInGb = (double) modelFile.length() / (1024 * 1024 * 1024);
+ modelName = String.format("%s (%.2f GB)", modelName, sizeInGb);
+ }
+ }
modelComboBox.setSelectedItem(modelName);
kwargsField.setText(config.getChatTemplateKwargs());
@@ -411,8 +452,21 @@ public class Main extends JFrame {
}
private void showSaveAsProfileDialog() {
- String modelName = (String) modelComboBox.getSelectedItem();
- String defaultName = modelName != null ? modelName : "";
+ String currentProfile = (String) profileComboBox.getSelectedItem();
+ String defaultName = (currentProfile != null && !currentProfile.isEmpty()) ? currentProfile : "";
+
+ if (defaultName.isEmpty()) {
+ String displayName = (String) modelComboBox.getSelectedItem();
+ String modelName = "";
+ if (displayName != null) {
+ if (displayName.contains(" (") && displayName.endsWith(" GB)")) {
+ modelName = displayName.substring(0, displayName.lastIndexOf(" ("));
+ } else {
+ modelName = displayName;
+ }
+ }
+ defaultName = modelName != null ? modelName : "";
+ }
String newName = InputDialog.showInputDialog(this, "Save profile as...", "Profile name:", defaultName);
diff --git a/src/main/java/cz/kamma/llamarunner/ProfileValidator.java b/src/main/java/cz/kamma/llamarunner/ProfileValidator.java
index 7522526..811a69e 100644
--- a/src/main/java/cz/kamma/llamarunner/ProfileValidator.java
+++ b/src/main/java/cz/kamma/llamarunner/ProfileValidator.java
@@ -8,7 +8,6 @@ import java.util.regex.Pattern;
public class ProfileValidator {
private static final int MAX_NAME_LENGTH = 100;
- private static final Pattern VALID_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_-]+$");
/**
* Validates a profile name.
@@ -27,10 +26,6 @@ public class ProfileValidator {
return "Profile name must be at most " + MAX_NAME_LENGTH + " characters";
}
- if (!VALID_NAME_PATTERN.matcher(trimmedName).matches()) {
- return "Profile name can only contain letters, numbers, underscores, and hyphens";
- }
-
return null;
}