1
0

Improve error handling and JSON parsing in ollama-list IPC handler, update settings.html

This commit is contained in:
2025-05-24 20:33:01 +02:00
parent 596907ab23
commit 850edb0460
2 changed files with 80 additions and 60 deletions

78
main.js
View File

@@ -69,7 +69,7 @@ function openSettings(win) {
parent: win, parent: win,
modal: true, modal: true,
width: 400, width: 400,
height: 300, height: 400,
resizable: false, resizable: false,
webPreferences: { webPreferences: {
preload: path.join(__dirname, 'preload.js'), preload: path.join(__dirname, 'preload.js'),
@@ -845,40 +845,56 @@ app.whenReady().then(() => {
store.set('intelligentCommitThreshold', value); store.set('intelligentCommitThreshold', value);
}); });
ipcMain.handle('ollama-list', async () => {
ipcMain.handle('ollama-list', async () => { // Versuche erst JSON-Ausgabe
return new Promise(resolve => { return new Promise(resolve => {
exec('ollama list --json', (err, stdout, stderr) => { exec('ollama list --json', (err, stdout, stderr) => {
if (err) { if (err) {
// Wenn ollama nicht gefunden → ENOENT // ENOENT → ollama CLI fehlt
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
return resolve({ status: 'no-cli' }); return resolve({ status: 'no-cli' });
}
// JSON-Modus nicht unterstützt? Dann Fallback auf plain text
return parsePlain();
} }
// Anderer Fehler: CLI lief, aber irgendwas ist schiefgelaufen try {
return resolve({ status: 'error', msg: stderr || err.message }); const lines = stdout
} .split('\n')
let models = []; .filter(l => l.trim())
try { .map(l => JSON.parse(l));
// JSON pro Zeile parsen return resolve({ status: 'ok', models: lines });
stdout.split('\n').forEach(line => { } catch (_) {
if (line.trim()) models.push(JSON.parse(line)); return parsePlain();
}); }
resolve({ status: 'ok', models }); });
} catch (parseErr) {
resolve({ status: 'error', msg: parseErr.message });
}
});
});
});
ipcMain.handle('ollama-pull', async (_e, model) => { // Fallback-Funktion: parst die tabellarische Ausgabe
return new Promise(resolve => { function parsePlain() {
exec(`ollama pull ${model}`, (err, stdout, stderr) => { exec('ollama list', (err2, out2, stderr2) => {
if (err) return resolve({ status: 'error', msg: stderr || err.message }); if (err2) {
resolve({ status: 'ok', msg: stdout }); if (err2.code === 'ENOENT') return resolve({ status: 'no-cli' });
return resolve({ status: 'error', msg: stderr2 || err2.message });
}
const models = [];
// Jede Zeile nach HEADER ignorieren, Spalten splitten
out2.split('\n').slice(1).forEach(line => {
const cols = line.trim().split(/\s{2,}/);
if (cols[0]) models.push({ name: cols[0] });
});
resolve({ status: 'ok', models });
});
}
});
});
ipcMain.handle('ollama-pull', async (_e, model) => {
return new Promise(resolve => {
exec(`ollama pull ${model}`, (err, stdout, stderr) => {
if (err) return resolve({ status: 'error', msg: stderr || err.message });
resolve({ status: 'ok', msg: stdout });
});
}); });
}); });
});
// … Ende der IPC-Handler … // … Ende der IPC-Handler …
}); });

View File

@@ -126,7 +126,7 @@
close.addEventListener('click', rollback); close.addEventListener('click', rollback);
const container = document.getElementById('ollama-model-selectors'); const container = document.getElementById('ollama-model-selectors');
const res = await window.electronAPI.ollamaList(); const res = await window.electronAPI.ollamaList();
if (res.status === 'no-cli') { if (res.status === 'no-cli') {
@@ -137,15 +137,17 @@
return; return;
} }
// Wenn CLI lief, aber Fehler beim Parsen, oder einfach keine Daten: if (res.status === 'error') {
const allModels = Array.isArray(res.models) ? res.models : []; container.innerHTML = `<div style="color:orange">Error fetching models: ${res.msg}</div>`;
// Filter für qwen2.5-coder return;
const qwenModels = allModels }
.map(m => m.name || m.model)
.filter(name => /^qwen2\.5-coder(:[\w\d\-.]+)?$/.test(name));
if (!qwenModels.length) { // Liste der Modell-Namen extrahieren
// Keine passenden Modelle → Pull-Buttons zeigen const names = res.models.map(m => m.name || m.model).filter(Boolean);
const qwen = names.filter(n => /^qwen2\.5-coder(:[\w\-.]+)?$/.test(n));
if (!qwen.length) {
// keine qwen2.5-coder → Pull-Buttons
container.innerHTML = ` container.innerHTML = `
<button id="pullCommitModelBtn" style="margin-bottom:8px;"> <button id="pullCommitModelBtn" style="margin-bottom:8px;">
ollama pull qwen2.5-coder:7b ollama pull qwen2.5-coder:7b
@@ -164,32 +166,34 @@
return; return;
} }
// Endlich: Dropdowns! // Dropdowns aufbauen
const makeOpts = (models, selected) => const makeOpts = (arr, sel) =>
models.map(m => `<option value="${m}"${m===selected?' selected':''}>${m}</option>`).join(''); arr.map(m => `<option ${m===sel?'selected':''}>${m}</option>`).join('');
// Defaults (oder aus Settings lesen) // Default-Auswahl aus Settings (oder erstes gefundenes)
const commitDefault = qwenModels.find(m => m.includes('7b')) || qwenModels[0]; const commitDefault = qwen.find(m=>m.includes('7b'))||qwen[0];
const readmeDefault = qwenModels.find(m => m.includes('32b')) || qwenModels[0]; const readmeDefault= qwen.find(m=>m.includes('32b'))||qwen[0];
const currentCommit = await window.settingsAPI.getCommitModel?.() || commitDefault; const currentCommit = await window.settingsAPI.getCommitModel?.() || commitDefault;
const currentReadme= await window.settingsAPI.getReadmeModel?.() || readmeDefault; const currentReadme= await window.settingsAPI.getReadmeModel?.() || readmeDefault;
container.innerHTML = ` container.innerHTML = `
<label><strong>Model for commit message generation:</strong></label> <label>Model for commit message generation:
<select id="commitModelSelect"> <select id="commitModelSelect">
${makeOpts(qwenModels, currentCommit)} ${makeOpts(qwen, currentCommit)}
</select> </select>
<br><label><strong>Model for README generation:</strong></label> </label><br>
<select id="readmeModelSelect"> <label>Model for README generation:
${makeOpts(qwenModels, currentReadme)} <select id="readmeModelSelect">
</select> ${makeOpts(qwen, currentReadme)}
`; </select>
document.getElementById('commitModelSelect').onchange = e => </label>`;
window.settingsAPI.setCommitModel(e.target.value);
document.getElementById('readmeModelSelect').onchange = e => document.getElementById('commitModelSelect')
window.settingsAPI.setReadmeModel(e.target.value); .addEventListener('change', e => window.settingsAPI.setCommitModel(e.target.value));
document.getElementById('readmeModelSelect')
.addEventListener('change', e => window.settingsAPI.setReadmeModel(e.target.value));
}); });
</script> </script>
</head> </head>
<body> <body>
<div class="dialog"> <div class="dialog">