Email-Triage: Lernen aus IMAP-Ordnern, manuelle Korrektur, reichere Daten
- Automatisches Triage-Lernen aus Archiv-Ordnern im Nacht-Ingest: retention_days=0 (Archiv) → wichtig, retention_days>0 → unwichtig - Drei neue Discord-Commands: /email triage-history, triage-correct, triage-search - StoreDecision speichert jetzt Datum + Body-Zusammenfassung (max 200 Zeichen) - MIME-Multipart-Parsing mit PDF-Attachment-Extraktion (FetchWithBodyAndAttachments) - Deterministische IDs basierend auf Absender+Betreff (idempotente Upserts) - Rueckwaertskompatibles Parsing fuer alte Triage-Eintraege ohne Datum/Body Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -328,7 +328,8 @@ func ClassifyImportance(msg Message, model string) bool {
|
||||
)
|
||||
|
||||
// Entscheidung für künftiges Lernen in Qdrant speichern
|
||||
if err := triage.StoreDecision(msg.Subject, msg.From, isImportant); err != nil {
|
||||
// Body ist bei ClassifyImportance nicht verfügbar (nur Envelope), daher leer.
|
||||
if err := triage.StoreDecision(msg.Subject, msg.From, msg.Date, "", isImportant); err != nil {
|
||||
slog.Warn("[Triage] Entscheidung nicht gespeichert", "fehler", err)
|
||||
}
|
||||
|
||||
@@ -646,3 +647,64 @@ func fallbackList(msgs []Message) string {
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// LearnFromFolders scannt die Archiv-Ordner eines Accounts und speichert Triage-Entscheidungen in Qdrant.
|
||||
// Ordner mit retention_days == 0 (Archiv/dauerhaft) → wichtig, retention_days > 0 → unwichtig.
|
||||
// Pro Ordner werden maximal die letzten 50 Emails verarbeitet.
|
||||
func LearnFromFolders(acc config.EmailAccount) (wichtig, unwichtig int, err error) {
|
||||
if len(acc.ArchiveFolders) == 0 {
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
cl, err := ConnectAccount(acc)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("IMAP verbinden: %w", err)
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
for _, af := range acc.ArchiveFolders {
|
||||
isImportant := af.RetentionDays == 0
|
||||
|
||||
msgs, err := cl.FetchWithBodyAndAttachments(af.IMAPFolder, 50)
|
||||
if err != nil {
|
||||
slog.Warn("[Triage-Learn] Ordner nicht lesbar", "ordner", af.IMAPFolder, "fehler", err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
if err := triage.StoreDecision(m.Subject, m.From, m.Date, m.Body, isImportant); err != nil {
|
||||
slog.Warn("[Triage-Learn] Speichern fehlgeschlagen", "betreff", m.Subject, "fehler", err)
|
||||
continue
|
||||
}
|
||||
if isImportant {
|
||||
wichtig++
|
||||
} else {
|
||||
unwichtig++
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("[Triage-Learn] Ordner verarbeitet",
|
||||
"account", accountLabel(acc),
|
||||
"ordner", af.IMAPFolder,
|
||||
"emails", len(msgs),
|
||||
"wichtig", isImportant,
|
||||
)
|
||||
}
|
||||
|
||||
return wichtig, unwichtig, nil
|
||||
}
|
||||
|
||||
// LearnFromFoldersAllAccounts führt LearnFromFolders für alle konfigurierten Accounts aus.
|
||||
func LearnFromFoldersAllAccounts() (wichtig, unwichtig int, err error) {
|
||||
accounts := config.AllEmailAccounts()
|
||||
for _, acc := range accounts {
|
||||
w, u, accErr := LearnFromFolders(acc)
|
||||
if accErr != nil {
|
||||
slog.Error("[Triage-Learn] Account fehlgeschlagen", "account", accountLabel(acc), "fehler", accErr)
|
||||
continue
|
||||
}
|
||||
wichtig += w
|
||||
unwichtig += u
|
||||
}
|
||||
return wichtig, unwichtig, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user