feat(v8.3): Memory Import aus Cloud-KIs + Batch-POST

- MemoryPanel: "Import"-Button öffnet Formular
- Jede Zeile wird ein eigener Gedächtnis-Eintrag (Batch-POST)
- Kategorie + Quelle (claude/gemini/chatgpt/import) wählbar
- Zeilen-Vorschau zeigt erkannte Einträge vor dem Speichern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-23 18:25:17 +02:00
parent df1ba748d4
commit 6f4f25480a
2 changed files with 126 additions and 41 deletions
+85 -4
View File
@@ -20,6 +20,15 @@
let editId = $state<string | null>(null)
let editContent = $state('')
let editCategory = $state('stable')
let importing = $state(false)
let importText = $state('')
let importCategory = $state('stable')
let importSource = $state('import')
let importBusy = $state(false)
const importLines = $derived(
importText.split('\n').map(l => l.trim()).filter(l => l.length > 0)
)
const filtered = $derived(
filter === 'all' ? memories : memories.filter(m => m.category === filter)
@@ -94,6 +103,26 @@
editId = m.id; editContent = m.content; editCategory = m.category
}
async function runImport() {
if (importLines.length === 0) return
importBusy = true
let ok = 0
for (const line of importLines) {
try {
const m = await api('/api/memory', {
method: 'POST',
body: JSON.stringify({ content: line, category: importCategory, source: importSource })
})
memories = [m, ...memories]
ok++
} catch {}
}
importBusy = false
importing = false
importText = ''
toast(`${ok} von ${importLines.length} Einträgen importiert`)
}
$effect(() => { load() })
</script>
@@ -102,12 +131,64 @@
<h1>Gedächtnis</h1>
<div class="sub">Fakten, Entscheidungen und Kontext — geteilt von allen KI-Tools via MCP.</div>
</div>
<button class="primary" style="flex-shrink:0;margin-top:4px"
onclick={() => { adding = !adding; newContent = '' }}>
{adding ? 'Abbrechen' : '+ Eintrag'}
</button>
<div class="flex gap-2" style="flex-shrink:0;margin-top:4px">
<button class="ghost" onclick={() => { importing = !importing; adding = false; importText = '' }}>
{importing ? 'Abbrechen' : '⇩ Import'}
</button>
<button class="primary" onclick={() => { adding = !adding; importing = false; newContent = '' }}>
{adding ? 'Abbrechen' : '+ Eintrag'}
</button>
</div>
</div>
<!-- Import form -->
{#if importing}
<div class="card" style="border-color:rgba(45,212,191,.25)">
<div class="card-h"><h3>Import aus Claude / Gemini / ChatGPT</h3></div>
<div class="card-sub" style="margin-bottom:10px">
Füge Erkenntnisse aus anderen KI-Sessions ein — jede Zeile wird ein eigener Eintrag.
</div>
<label>Einträge (eine Zeile = ein Eintrag)</label>
<textarea
rows="8"
placeholder={"Tobi arbeitet am liebsten abends.\nProjektsprache: Deutsch.\nBosgame M5 läuft mit Ubuntu 26.04.\n..."}
style="width:100%;box-sizing:border-box;resize:vertical;margin-bottom:10px;font-family:var(--mono);font-size:12.5px"
bind:value={importText}
></textarea>
<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:14px">
<div style="flex:1;min-width:160px">
<label>Kategorie für alle Einträge</label>
<select bind:value={importCategory} style="margin-bottom:0">
<option value="user">Über mich — Wer du bist, Präferenzen</option>
<option value="instruction">Verhalten — Regeln für alle KI-Tools</option>
<option value="stable">Stabil — Projektfakten</option>
<option value="versioned">Versioniert — Tech-Versionen</option>
<option value="ephemeral">Temporär — 7 Tage, dann weg</option>
</select>
</div>
<div style="flex:1;min-width:120px">
<label>Quelle</label>
<select bind:value={importSource} style="margin-bottom:0">
<option value="import">import</option>
<option value="claude">claude</option>
<option value="gemini">gemini</option>
<option value="chatgpt">chatgpt</option>
<option value="manual">manual</option>
</select>
</div>
</div>
{#if importLines.length > 0}
<div class="card-sub" style="margin-bottom:10px">{importLines.length} Eintrag/Einträge erkannt</div>
{/if}
<div class="btn-row">
<button class="primary" onclick={runImport} disabled={importLines.length === 0 || importBusy}>
{importBusy ? 'Importiere…' : `${importLines.length} Einträge speichern`}
</button>
<button class="ghost" onclick={() => { importing = false; importText = '' }}>Abbrechen</button>
</div>
</div>
{/if}
<!-- Add form -->
{#if adding}
<div class="card">
+41 -37
View File
File diff suppressed because one or more lines are too long