From 9f909192d2c0517f5c6ddbe0286422d62330050a Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Wed, 22 Apr 2026 17:01:38 +0200 Subject: [PATCH] some UI tweaks --- config.properties | 3 +- profiles.json | 202 +++++++----------- .../java/cz/kamma/llamarunner/AppConfig.java | 13 ++ src/main/java/cz/kamma/llamarunner/Main.java | 69 ++++-- 4 files changed, 145 insertions(+), 142 deletions(-) diff --git a/config.properties b/config.properties index d1212ea..f84662b 100644 --- a/config.properties +++ b/config.properties @@ -1,5 +1,6 @@ #Llama Runner Configuration -#Tue Apr 14 16:56:36 CEST 2026 +#Wed Apr 22 16:58:54 CEST 2026 +lastProfile=Exaone4 windowHeight=1281 windowWidth=665 windowX=1895 diff --git a/profiles.json b/profiles.json index 9cd609d..86c4038 100644 --- a/profiles.json +++ b/profiles.json @@ -21,28 +21,6 @@ "fit": false, "reasoning": false }, - "Qwen3.5-q6k-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.6, - "topP": 0.95, - "topK": 20, - "minP": 0.0, - "ctxSize": 180000, - "enableThinking": false, - "modelPath": "/home/kamma/models/Qwen3.5-35B-A3B-Q6_K.gguf", - "chatTemplateKwargs": "{\"enable_thinking\": false}", - "ngl": 999, - "fit": true, - "reasoning": false - }, "QwenCoderNext-160k": { "host": "0.0.0.0", "port": 3080, @@ -87,28 +65,6 @@ "fit": false, "reasoning": false }, - "Qwen3.5 q6xl 160k": { - "host": "0.0.0.0", - "port": 3080, - "parallel": 1, - "batchSize": 2048, - "threads": 99, - "flashAttention": true, - "kvUnified": true, - "cacheTypeK": "turbo3", - "cacheTypeV": "turbo3", - "temperature": 0.6, - "topP": 0.95, - "topK": 20, - "minP": 0.0, - "ctxSize": 160000, - "enableThinking": false, - "modelPath": "/home/kamma/models/Qwen3.5-35B-A3B-UD-Q6_K_XL.gguf", - "chatTemplateKwargs": "{\"enable_thinking\": false}", - "ngl": -1, - "fit": true, - "reasoning": false - }, "gpt-oss-20b-160k": { "host": "0.0.0.0", "port": 3080, @@ -175,46 +131,24 @@ "fit": true, "reasoning": false }, - "Qwen3-Coder-Next-UD-Q2KXL-160k": { - "host": "0.0.0.0", - "port": 3080, - "parallel": 1, - "batchSize": 2048, - "threads": 99, - "flashAttention": true, - "kvUnified": true, - "cacheTypeK": "turbo3", - "cacheTypeV": "turbo3", - "temperature": 0.6, - "topP": 0.95, - "topK": 20, - "minP": 0.0, - "ctxSize": 160000, - "enableThinking": false, - "modelPath": "/home/kamma/models/Qwen3-Coder-Next-UD-Q2_K_XL.gguf", - "chatTemplateKwargs": "{\"enable_thinking\": true}", - "ngl": -1, - "fit": true, - "reasoning": false - }, "Qwen3-Coder-Next-UD-Q3KXL-160k": { "host": "0.0.0.0", "port": 3080, "parallel": 1, - "batchSize": 2048, + "batchSize": 4096, "threads": 99, "flashAttention": true, "kvUnified": true, - "cacheTypeK": "turbo3", - "cacheTypeV": "turbo3", - "temperature": 0.6, + "cacheTypeK": "q8_0", + "cacheTypeV": "q8_0", + "temperature": 1.0, "topP": 0.95, - "topK": 20, - "minP": 0.0, + "topK": 40, + "minP": 0.01, "ctxSize": 160000, "enableThinking": false, "modelPath": "/home/kamma/models/Qwen3-Coder-Next-UD-Q3_K_XL.gguf", - "chatTemplateKwargs": "{\"enable_thinking\": true}", + "chatTemplateKwargs": "", "ngl": -1, "fit": true, "reasoning": false @@ -227,63 +161,19 @@ "threads": 99, "flashAttention": true, "kvUnified": true, - "cacheTypeK": "turbo3", - "cacheTypeV": "turbo3", - "temperature": 0.6, + "cacheTypeK": "q8_0", + "cacheTypeV": "q8_0", + "temperature": 1.0, "topP": 0.95, - "topK": 20, - "minP": 0.0, + "topK": 40, + "minP": 0.01, "ctxSize": 160000, "enableThinking": false, "modelPath": "/home/kamma/models/Qwen3-Coder-Next-UD-Q4_K_XL.gguf", "chatTemplateKwargs": "", "ngl": -1, "fit": true, - "reasoning": true - }, - "Qwen35-35B-A3B-Q6K-turbo4-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": "{\"enable_thinking\": true}", - "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 + "reasoning": false }, "gemma-4-31B-it-UD-Q6KXL-54k": { "host": "0.0.0.0", @@ -350,5 +240,71 @@ "ngl": 99, "fit": false, "reasoning": true + }, + "Exaone4": { + "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": 131072, + "enableThinking": false, + "modelPath": "/home/kamma/models/EXAONE-4.0-32B-GGUF-Q6_K.gguf", + "chatTemplateKwargs": "", + "ngl": 99, + "fit": false, + "reasoning": true + }, + "Qwen3.6-35B-A3B-UD-Q6_K_XL-FIT": { + "host": "0.0.0.0", + "port": 3080, + "parallel": 1, + "batchSize": 4096, + "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/Qwen3.6-35B-A3B-UD-Q6_K_XL.gguf", + "chatTemplateKwargs": "", + "ngl": 99, + "fit": false, + "reasoning": true + }, + "Qwen3.6-35B-A3B-UD-Q5_K_XL-FULL": { + "host": "0.0.0.0", + "port": 3080, + "parallel": 1, + "batchSize": 4096, + "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/Qwen3.6-35B-A3B-UD-Q5_K_XL.gguf", + "chatTemplateKwargs": "", + "ngl": 99, + "fit": false, + "reasoning": true } } \ No newline at end of file diff --git a/src/main/java/cz/kamma/llamarunner/AppConfig.java b/src/main/java/cz/kamma/llamarunner/AppConfig.java index 1318050..a482db4 100644 --- a/src/main/java/cz/kamma/llamarunner/AppConfig.java +++ b/src/main/java/cz/kamma/llamarunner/AppConfig.java @@ -19,6 +19,7 @@ public class AppConfig { private int windowHeight; private int windowX; private int windowY; + private String lastProfile; private final ConfigLocation configLocation; public AppConfig() { @@ -47,6 +48,7 @@ public class AppConfig { windowHeight = Integer.parseInt(props.getProperty("windowHeight", String.valueOf(DEFAULT_HEIGHT))); windowX = Integer.parseInt(props.getProperty("windowX", String.valueOf(DEFAULT_X))); windowY = Integer.parseInt(props.getProperty("windowY", String.valueOf(DEFAULT_Y))); + lastProfile = props.getProperty("lastProfile", ""); } catch (IOException | NumberFormatException e) { // Use default values on error } @@ -60,6 +62,9 @@ public class AppConfig { props.setProperty("windowHeight", String.valueOf(windowHeight)); props.setProperty("windowX", String.valueOf(windowX)); props.setProperty("windowY", String.valueOf(windowY)); + if (lastProfile != null) { + props.setProperty("lastProfile", lastProfile); + } try (FileOutputStream fos = new FileOutputStream(configLocation.getConfigPropertiesFile())) { props.store(fos, "Llama Runner Configuration"); @@ -99,4 +104,12 @@ public class AppConfig { public void setWindowY(int windowY) { this.windowY = windowY; } + + public String getLastProfile() { + return lastProfile; + } + + public void setLastProfile(String lastProfile) { + this.lastProfile = lastProfile; + } } diff --git a/src/main/java/cz/kamma/llamarunner/Main.java b/src/main/java/cz/kamma/llamarunner/Main.java index d2da226..21aacdb 100644 --- a/src/main/java/cz/kamma/llamarunner/Main.java +++ b/src/main/java/cz/kamma/llamarunner/Main.java @@ -13,6 +13,8 @@ import java.awt.Toolkit; import java.awt.Image; import javax.imageio.ImageIO; import java.awt.datatransfer.StringSelection; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; @@ -130,6 +132,10 @@ public class Main extends JFrame { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { + String profile = (String) profileComboBox.getSelectedItem(); + if (profile != null) { + appConfig.setLastProfile(profile); + } saveWindowConfig(); dispose(); System.exit(0); @@ -140,8 +146,12 @@ public class Main extends JFrame { SwingUtilities.invokeLater(() -> { loadModels(); loadProfiles(); - if (profileComboBox.getItemCount() > 0) { + if (appConfig.getLastProfile() != null && !appConfig.getLastProfile().isEmpty()) { + profileComboBox.setSelectedItem(appConfig.getLastProfile()); + } else if (profileComboBox.getItemCount() > 0) { profileComboBox.setSelectedIndex(0); + } + if (profileComboBox.getSelectedItem() != null) { showLoadProfileDialog(); } updateCommandPreview(); @@ -291,16 +301,23 @@ public class Main extends JFrame { } private void loadProfiles() { + String selectedItem = (String) profileComboBox.getSelectedItem(); + // Remove listener temporarily to prevent triggering during load profileComboBox.removeActionListener(profileChangeListener); try { + profileComboBox.removeAllItems(); List profiles = profileManager.listProfiles(); profiles.sort(String::compareToIgnoreCase); for (String name : profiles) { profileComboBox.addItem(name); } + if (selectedItem != null) { + profileComboBox.setSelectedItem(selectedItem); + } + // Re-add listener after loading profileComboBox.addActionListener(profileChangeListener); } catch (Exception e) { @@ -318,6 +335,7 @@ public class Main extends JFrame { } String selectedItem = (String) profileComboBox.getSelectedItem(); if (selectedItem != null && !selectedItem.isEmpty()) { + appConfig.setLastProfile(selectedItem); showLoadProfileDialog(); } } @@ -349,6 +367,7 @@ public class Main extends JFrame { return; } saveProfileToName(currentProfile); + loadProfiles(); JOptionPane.showMessageDialog(this, "Profile saved!"); } catch (IOException e) { @@ -641,7 +660,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; hostField = new JTextField("0.0.0.0", 15); hostField.setCaretColor(Color.WHITE); - hostField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(hostField); panel.add(hostField, gbc); gbc.gridx = 0; @@ -653,7 +672,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; portField = new JTextField("3080", 10); portField.setCaretColor(Color.WHITE); - portField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(portField); panel.add(portField, gbc); return panel; @@ -677,7 +696,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; parallelField = new JTextField("1", 10); parallelField.setCaretColor(Color.WHITE); - parallelField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(parallelField); panel.add(parallelField, gbc); gbc.gridx = 0; @@ -689,7 +708,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; batchSizeField = new JTextField("4096", 10); batchSizeField.setCaretColor(Color.WHITE); - batchSizeField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(batchSizeField); panel.add(batchSizeField, gbc); gbc.gridx = 0; @@ -701,7 +720,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; threadsField = new JTextField("99", 10); threadsField.setCaretColor(Color.WHITE); - threadsField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(threadsField); panel.add(threadsField, gbc); gbc.gridx = 0; @@ -769,7 +788,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; nglField = new JTextField("-1", 10); nglField.setCaretColor(Color.WHITE); - nglField.getDocument().addDocumentListener(createNglDocumentListener()); + addFocusUpdateListener(nglField); panel.add(nglField, gbc); // Fit parameter @@ -816,7 +835,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; tempField = new JTextField("0.6", 10); tempField.setCaretColor(Color.WHITE); - tempField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(tempField); panel.add(tempField, gbc); gbc.gridx = 0; @@ -828,7 +847,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; topPField = new JTextField("0.95", 10); topPField.setCaretColor(Color.WHITE); - topPField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(topPField); panel.add(topPField, gbc); gbc.gridx = 0; @@ -840,7 +859,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; topKField = new JTextField("20", 10); topKField.setCaretColor(Color.WHITE); - topKField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(topKField); panel.add(topKField, gbc); gbc.gridx = 0; @@ -852,7 +871,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; minPField = new JTextField("0.00", 10); minPField.setCaretColor(Color.WHITE); - minPField.addActionListener(e -> updateCommandPreview()); + addFocusUpdateListener(minPField); panel.add(minPField, gbc); gbc.gridx = 0; @@ -864,8 +883,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; ctxSizeField = new JTextField("180000", 10); ctxSizeField.setCaretColor(Color.WHITE); - ctxSizeField.addActionListener(e -> updateCommandPreview()); - ctxSizeField.getDocument().addDocumentListener(new PreviewUpdateListener(this::updateCommandPreview)); + addFocusUpdateListener(ctxSizeField); panel.add(ctxSizeField, gbc); gbc.gridx = 0; @@ -878,7 +896,7 @@ public class Main extends JFrame { gbc.weightx = 1.0; kwargsField = new JTextField("{\"enable_thinking\": true}"); kwargsField.setCaretColor(Color.WHITE); - kwargsField.getDocument().addDocumentListener(new PreviewUpdateListener(this::updateCommandPreview)); + addFocusUpdateListener(kwargsField); panel.add(kwargsField, gbc); return panel; @@ -924,8 +942,18 @@ public class Main extends JFrame { if (isProfileLoading) { return; } - String command = buildCommand(); - commandPreviewArea.setText(command); + try { + String error = validateCurrentConfig(); + if (error != null) { + JOptionPane.showMessageDialog(this, error, "Validation Error", JOptionPane.ERROR_MESSAGE); + return; + } + String command = buildCommand(); + commandPreviewArea.setText(command); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(this, "Please enter valid numeric values.", "Validation Error", + JOptionPane.ERROR_MESSAGE); + } } private void setNglFieldText(String text) { @@ -933,8 +961,13 @@ public class Main extends JFrame { updateCommandPreview(); } - private javax.swing.event.DocumentListener createNglDocumentListener() { - return new PreviewUpdateListener(this::updateCommandPreview); + private void addFocusUpdateListener(JTextField field) { + field.addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + updateCommandPreview(); + } + }); } private void copyCommandToClipboard() {