feat(v9): deterministischer Memory-Kurator (Dedupe) statt LLM-Cron
- routers/memory.py: POST /api/memory/dedupe — findet Dubletten (exakt/ enthalten/ähnlich via SequenceMatcher) je Kategorie, behält den vollständigsten Eintrag. Dry-Run (apply:false) + Anwenden. Kein LLM. - MemoryPanel: "🧹 Aufräumen"-Button (Vorschau → Bestätigung → löschen). Grund: LLM-Cron-Kurator hat Edits nur halluziniert/als Text ausgegeben statt auszuführen (Hermes 4 + Qwen). Deterministisch = verlässlich. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,26 @@
|
||||
editId = m.id; editContent = m.content; editCategory = m.category
|
||||
}
|
||||
|
||||
// Deterministischer Kurator: Dubletten (exakt/enthalten/ähnlich) je Kategorie zusammenführen
|
||||
let deduping = $state(false)
|
||||
async function dedupe() {
|
||||
deduping = true
|
||||
try {
|
||||
const preview = await api('/api/memory/dedupe', { method: 'POST', body: JSON.stringify({ apply: false }) })
|
||||
if (preview.duplicate_count === 0) { toast('Keine Dubletten gefunden 🎉'); return }
|
||||
const ok = await confirmModal({
|
||||
title: `${preview.duplicate_count} Dubletten entfernen?`,
|
||||
body: `${preview.duplicate_count} doppelte Einträge werden gelöscht; die ${preview.groups.length} vollständigeren bleiben erhalten. Nur exakte/enthaltene/sehr ähnliche Einträge derselben Kategorie.`,
|
||||
danger: true,
|
||||
})
|
||||
if (!ok) return
|
||||
const res = await api('/api/memory/dedupe', { method: 'POST', body: JSON.stringify({ apply: true }) })
|
||||
toast(`${res.removed} Dubletten entfernt`)
|
||||
await load()
|
||||
} catch (e: any) { toast('Fehler: ' + e.message, true) }
|
||||
finally { deduping = false }
|
||||
}
|
||||
|
||||
async function runImport() {
|
||||
if (importLines.length === 0) return
|
||||
importBusy = true
|
||||
@@ -132,6 +152,9 @@
|
||||
<div class="sub">Fakten, Entscheidungen und Kontext — geteilt von allen KI-Tools via MCP.</div>
|
||||
</div>
|
||||
<div class="flex gap-2" style="flex-shrink:0;margin-top:4px">
|
||||
<button class="ghost" onclick={dedupe} disabled={deduping} title="Doppelte Einträge zusammenführen">
|
||||
{deduping ? '…' : '🧹 Aufräumen'}
|
||||
</button>
|
||||
<button class="ghost" onclick={() => { importing = !importing; adding = false; importText = '' }}>
|
||||
{importing ? 'Abbrechen' : '⇩ Import'}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user