Asetukset-välilehti: kaikki LLM-parametrit muokattavissa UI:sta
Uusi "Asetukset"-tab jossa: - System Prompt (tekstikenttä, Courier-fontti) - Temperature (slider 0-1.5, reaaliaikainen arvo) - Top-K (slider 1-100) - Repetition Penalty (slider 1.0-2.0) - Max Tokens (slider 64-4096) - Stop-sekvenssit (yksi per rivi) - Mallinvalinta (dropdown: 1.5B/3B/7B Q4/7B) - "Palauta oletukset" -nappi Kaikki tallentuvat localStorageen (kpn-settings). Jokainen parametri selitetty hint-tekstillä. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
67
network-poc/frontend/src/components/Settings.astro
Normal file
67
network-poc/frontend/src/components/Settings.astro
Normal file
@@ -0,0 +1,67 @@
|
||||
<!-- Asetukset-paneeli: kaikki LLM-parametrit muokattavissa -->
|
||||
<div id="panel-settings" class="panel">
|
||||
<div style="max-width:800px;margin:0 auto;padding:20px">
|
||||
<h2 style="color:#e6edf3;margin-bottom:16px">Asetukset</h2>
|
||||
<p style="color:#8b949e;margin-bottom:20px;font-size:14px">Kaikki kielimallin toimintaan vaikuttavat parametrit. Muutokset tallentuvat automaattisesti.</p>
|
||||
|
||||
<!-- System prompt -->
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-title">System Prompt</h3>
|
||||
<p class="settings-desc">Kielimallin perusohje joka lähetetään jokaisessa pyynnössä. Määrittää mallin käyttäytymisen.</p>
|
||||
<textarea id="set-system-prompt" class="settings-textarea" rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Sampling -->
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-title">Sampling-parametrit</h3>
|
||||
<p class="settings-desc">Kontrolloi miten malli valitsee seuraavan tokenin. <a href="#guide" onclick="switchTab('guide')" style="color:var(--accent)">Lue lisää oppaasta.</a></p>
|
||||
<div class="settings-grid">
|
||||
<div>
|
||||
<label class="settings-label">Temperature <span id="set-temp-val" class="settings-val">0.7</span></label>
|
||||
<input type="range" id="set-temperature" min="0" max="1.5" step="0.1" value="0.7" class="settings-slider">
|
||||
<div class="settings-hint">0 = deterministic, 0.7 = balanced, 1.5 = creative</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="settings-label">Top-K <span id="set-topk-val" class="settings-val">40</span></label>
|
||||
<input type="range" id="set-topk" min="1" max="100" step="1" value="40" class="settings-slider">
|
||||
<div class="settings-hint">Montako tokenia huomioidaan. 1 = greedy, 40 = oletus</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="settings-label">Repetition Penalty <span id="set-rep-val" class="settings-val">1.15</span></label>
|
||||
<input type="range" id="set-repeat" min="1.0" max="2.0" step="0.05" value="1.15" class="settings-slider">
|
||||
<div class="settings-hint">Estää toistoa. 1.0 = ei rangaistusta, 1.15 = oletus</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="settings-label">Max Tokens <span id="set-maxtok-val" class="settings-val">1024</span></label>
|
||||
<input type="range" id="set-maxtokens" min="64" max="4096" step="64" value="1024" class="settings-slider">
|
||||
<div class="settings-hint">Vastauksen maksimipituus tokeneina</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stop-sekvenssit -->
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-title">Stop-sekvenssit</h3>
|
||||
<p class="settings-desc">Generointi katkeaa kun malli tuottaa jonkin näistä. Yksi per rivi.</p>
|
||||
<textarea id="set-stop-sequences" class="settings-textarea" rows="4"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Malli -->
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-title">Malli (Ollama)</h3>
|
||||
<p class="settings-desc">Natiivisolmun käyttämä kielimalli. Muutos vaatii native-noden uudelleenkäynnistyksen.</p>
|
||||
<select id="set-model" class="settings-select">
|
||||
<option value="qwen2.5-coder:1.5b">Qwen2.5-Coder:1.5B (~80 tok/s, ~1GB)</option>
|
||||
<option value="qwen2.5-coder:3b">Qwen2.5-Coder:3B (~50 tok/s, ~2GB)</option>
|
||||
<option value="qwen2.5-coder:7b-instruct-q4_K_M">Qwen2.5-Coder:7B Q4 (~30 tok/s, ~4GB)</option>
|
||||
<option value="qwen2.5-coder:7b">Qwen2.5-Coder:7B (~20 tok/s, ~7GB)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Reset -->
|
||||
<div style="margin-top:24px;padding-top:16px;border-top:1px solid var(--border)">
|
||||
<button class="btn btn-red" onclick="resetSettings()" style="padding:6px 16px">Palauta oletukset</button>
|
||||
<span style="color:#8b949e;font-size:12px;margin-left:8px">Palauttaa kaikki parametrit oletusarvoihin</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,6 +5,7 @@ import Terminal from "../components/Terminal.astro";
|
||||
import Editor from "../components/Editor.astro";
|
||||
import Guide from "../components/Guide.astro";
|
||||
import AgentBar from "../components/AgentBar.astro";
|
||||
import Settings from "../components/Settings.astro";
|
||||
---
|
||||
<!DOCTYPE html>
|
||||
<html lang="fi">
|
||||
@@ -30,6 +31,7 @@ import AgentBar from "../components/AgentBar.astro";
|
||||
<div class="tab active" onclick="switchTab('agents')">Agentit</div>
|
||||
<div class="tab" onclick="switchTab('editor')">Editor</div>
|
||||
<div class="tab" onclick="switchTab('guide')">Opas</div>
|
||||
<div class="tab" onclick="switchTab('settings')">Asetukset</div>
|
||||
</div>
|
||||
|
||||
<!-- Agents-paneeli -->
|
||||
@@ -41,6 +43,7 @@ import AgentBar from "../components/AgentBar.astro";
|
||||
|
||||
<Editor />
|
||||
<Guide />
|
||||
<Settings />
|
||||
</div>
|
||||
|
||||
<script is:inline>
|
||||
@@ -95,6 +98,19 @@ Provide a brief risk assessment with severity (low/medium/high/critical).` },
|
||||
function saveAgents() { localStorage.setItem('kpn-agents', JSON.stringify(agents)); }
|
||||
function getAgentModel(name) { const a = agents[name]; return a ? a.model : name; }
|
||||
|
||||
// LLM-asetukset (localStorage-persistenssi)
|
||||
const defaultSettings = {
|
||||
systemPrompt: "You are a coding assistant. Respond with ONLY code. No explanations, no markdown fences, no 'Please note' text. Only working code with proper imports.",
|
||||
temperature: 0.7,
|
||||
topK: 40,
|
||||
repeatPenalty: 1.15,
|
||||
maxTokens: 1024,
|
||||
stopSequences: "\\n###\\n\\nExplanation\\nNote:\\nPlease note\\nThis is a basic\\n```\\n\\n\\n// Example\\n# Example",
|
||||
model: "qwen2.5-coder:3b",
|
||||
};
|
||||
let settings = JSON.parse(localStorage.getItem('kpn-settings') || 'null') || { ...defaultSettings };
|
||||
function saveSettings() { localStorage.setItem('kpn-settings', JSON.stringify(settings)); }
|
||||
|
||||
// === Tab switching ===
|
||||
window.switchTab = function(tab) {
|
||||
document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
|
||||
@@ -800,6 +816,58 @@ Provide a brief risk assessment with severity (low/medium/high/critical).` },
|
||||
}
|
||||
return html;
|
||||
}
|
||||
// === Settings panel ===
|
||||
function initSettings() {
|
||||
const els = {
|
||||
systemPrompt: document.getElementById('set-system-prompt'),
|
||||
temperature: document.getElementById('set-temperature'),
|
||||
tempVal: document.getElementById('set-temp-val'),
|
||||
topK: document.getElementById('set-topk'),
|
||||
topkVal: document.getElementById('set-topk-val'),
|
||||
repeat: document.getElementById('set-repeat'),
|
||||
repVal: document.getElementById('set-rep-val'),
|
||||
maxTokens: document.getElementById('set-maxtokens'),
|
||||
maxtokVal: document.getElementById('set-maxtok-val'),
|
||||
stopSeq: document.getElementById('set-stop-sequences'),
|
||||
model: document.getElementById('set-model'),
|
||||
};
|
||||
if (!els.systemPrompt) return;
|
||||
|
||||
// Lataa arvot
|
||||
els.systemPrompt.value = settings.systemPrompt;
|
||||
els.temperature.value = settings.temperature;
|
||||
els.tempVal.textContent = settings.temperature;
|
||||
els.topK.value = settings.topK;
|
||||
els.topkVal.textContent = settings.topK;
|
||||
els.repeat.value = settings.repeatPenalty;
|
||||
els.repVal.textContent = settings.repeatPenalty;
|
||||
els.maxTokens.value = settings.maxTokens;
|
||||
els.maxtokVal.textContent = settings.maxTokens;
|
||||
els.stopSeq.value = settings.stopSequences.replace(/\\n/g, '\n');
|
||||
els.model.value = settings.model;
|
||||
|
||||
// Tallenna muutokset
|
||||
els.systemPrompt.oninput = () => { settings.systemPrompt = els.systemPrompt.value; saveSettings(); };
|
||||
els.temperature.oninput = () => { settings.temperature = +els.temperature.value; els.tempVal.textContent = settings.temperature; saveSettings(); };
|
||||
els.topK.oninput = () => { settings.topK = +els.topK.value; els.topkVal.textContent = settings.topK; saveSettings(); };
|
||||
els.repeat.oninput = () => { settings.repeatPenalty = +els.repeat.value; els.repVal.textContent = settings.repeatPenalty; saveSettings(); };
|
||||
els.maxTokens.oninput = () => { settings.maxTokens = +els.maxTokens.value; els.maxtokVal.textContent = settings.maxTokens; saveSettings(); };
|
||||
els.stopSeq.oninput = () => { settings.stopSequences = els.stopSeq.value.replace(/\n/g, '\\n'); saveSettings(); };
|
||||
els.model.onchange = () => { settings.model = els.model.value; saveSettings(); };
|
||||
}
|
||||
// Alustetaan kun settings-tab avataan
|
||||
const origSwitchTab = window.switchTab;
|
||||
window.switchTab = function(tab) {
|
||||
origSwitchTab(tab);
|
||||
if (tab === 'settings') initSettings();
|
||||
};
|
||||
|
||||
window.resetSettings = function() {
|
||||
if (!confirm('Palautetaanko kaikki asetukset oletuksiin?')) return;
|
||||
settings = { ...defaultSettings };
|
||||
saveSettings();
|
||||
initSettings();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -165,6 +165,34 @@ body {
|
||||
box-shadow: 0 0 25px rgba(88,166,255,0.8);
|
||||
}
|
||||
|
||||
/* Settings */
|
||||
.settings-section {
|
||||
margin-bottom: 24px; padding: 16px; background: var(--panel);
|
||||
border: 1px solid var(--border); border-radius: 6px;
|
||||
}
|
||||
.settings-title { color: #e6edf3; font-size: 15px; margin-bottom: 4px; }
|
||||
.settings-desc { color: #8b949e; font-size: 13px; margin-bottom: 12px; }
|
||||
.settings-label { color: var(--text); font-size: 13px; display: block; margin-bottom: 4px; }
|
||||
.settings-val { color: var(--accent); font-weight: 600; float: right; }
|
||||
.settings-hint { color: #8b949e; font-size: 11px; margin-top: 2px; }
|
||||
.settings-textarea {
|
||||
width: 100%; background: var(--bg); color: var(--text);
|
||||
border: 1px solid var(--border); border-radius: 4px;
|
||||
padding: 8px; font-size: 13px; font-family: 'Courier New', monospace;
|
||||
resize: vertical;
|
||||
}
|
||||
.settings-select {
|
||||
width: 100%; background: var(--bg); color: var(--text);
|
||||
border: 1px solid var(--border); border-radius: 4px;
|
||||
padding: 8px; font-size: 13px;
|
||||
}
|
||||
.settings-slider {
|
||||
width: 100%; accent-color: var(--accent);
|
||||
}
|
||||
.settings-grid {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes blink { 0%,100% { opacity:1 } 50% { opacity:0 } }
|
||||
@keyframes spin { to { transform: rotate(360deg) } }
|
||||
|
||||
Reference in New Issue
Block a user