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; }