Improve error handling and JSON parsing in ollama-list IPC handler, update settings.html
This commit is contained in:
78
main.js
78
main.js
@@ -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 …
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user