feat: Verlauf-Log beim Tag archivieren sichern und leeren

"Tag archivieren" archiviert jetzt zusaetzlich das Verlauf-Log (Kopie nach
telefon/verlauf-archiv/verlauf_JJJJMMTT-HHMMSS.log) und leert es danach -
frische Verlaufsansicht fuer den neuen Tag. Das dauerhafte, unveraenderliche
audit.log ist davon nicht betroffen, das behaelt ohnehin alles fuer immer.

Live getestet: 530 Zeilen archiviert, Log korrekt geleert (nur noch die
Bestaetigungszeile drin).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs
This commit is contained in:
Jeuner 2026-08-25 00:00:36 +02:00
parent bc588072bd
commit 9f64d94b3f
3 changed files with 30 additions and 2 deletions

View file

@ -11,12 +11,15 @@ jedes Ereignis zusaetzlich unveraenderlich nach audit.log, siehe pipe.audit.
from __future__ import annotations
import json
import shutil
from datetime import datetime
from pathlib import Path
from . import audit, config
DATEI = config.TELEFON / "verlauf.log"
MAX_ZEILEN = 2000 # darüber wird beim Schreiben gekürzt
ARCHIV_ORDNER = config.TELEFON / "verlauf-archiv"
def schreibe(art: str, text: str, **felder) -> None:
@ -59,3 +62,20 @@ def kuerze() -> None:
DATEI.write_text("\n".join(zeilen[-MAX_ZEILEN:]) + "\n", encoding="utf-8")
except Exception:
pass
def archiviere_und_leere() -> Path | None:
"""Sichert den aktuellen Verlauf als Kopie und leert ihn danach - fuer
einen frischen Verlauf nach "Tag archivieren". Das dauerhafte audit.log
ist davon unberuehrt (behaelt ohnehin alles). Wirft nie. Gibt den Pfad
der Archivkopie zurueck, oder None wenn nichts zu sichern war."""
try:
if not DATEI.is_file() or not DATEI.stat().st_size:
return None
ARCHIV_ORDNER.mkdir(parents=True, exist_ok=True)
ziel = ARCHIV_ORDNER / f"verlauf_{datetime.now():%Y%m%d-%H%M%S}.log"
shutil.copy2(DATEI, ziel)
DATEI.write_text("", encoding="utf-8")
return ziel
except Exception:
return None

View file

@ -298,7 +298,13 @@ class Handler(BaseHTTPRequestHandler):
_, export_anzahl = export.exportiere()
if export_anzahl:
protokoll.schreibe("export", f"{export_anzahl} bewertete Anrufe exportiert")
self._json({"ok": True, "anzahl": anzahl, "simuliert": True, "export_anzahl": export_anzahl})
# Verlauf-Log sichern + leeren, fuer eine frische Ansicht ab jetzt.
# audit.log (dauerhaft, unveraenderlich) ist davon nicht betroffen.
log_archiv = protokoll.archiviere_und_leere()
if log_archiv:
protokoll.schreibe("system", f"Verlauf archiviert nach {log_archiv.name} und geleert")
self._json({"ok": True, "anzahl": anzahl, "simuliert": True, "export_anzahl": export_anzahl,
"log_archiviert": log_archiv.name if log_archiv else None})
return
if pfad == "/api/export":
ziel, anzahl = export.exportiere()
@ -546,7 +552,7 @@ color:var(--gut);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:
</style></head><body><div class="wrap">
<header><h1>Logpy:AgentOne Anruf-Leitstand</h1>
<button class="sicher-btn" id="sicherBtn" title="Namen, Nummern, Anliegen und Transkripte unscharf - fuer Bildschirmaufnahmen/Screenshots">🙈 Sicher-Modus</button>
<button class="archiv-btn" id="archivBtn" title="Erledigte Anrufe vom Board raeumen (simuliert, nichts wird geloescht) - bewertete Anrufe werden dabei als Trainingsdaten exportiert">🗄 Tag archivieren</button>
<button class="archiv-btn" id="archivBtn" title="Erledigte Anrufe vom Board raeumen (simuliert, nichts wird geloescht) - bewertete Anrufe werden als Trainingsdaten exportiert, das Verlauf-Log wird gesichert und geleert">🗄 Tag archivieren</button>
<button class="export-btn" id="exportBtn" title="Bewertete Anrufe (👍/👎) als JSONL-Trainingsdaten exportieren, unabhaengig vom Archivieren">📤 Bewertungen exportieren</button>
<span class="stand" id="stand"></span>
<select class="modell-select" id="modellSelect" title="Kategorisierungs-Modell fuer neue Anrufe - Aenderung greift sofort, kein Neustart noetig"></select>
@ -863,6 +869,7 @@ document.getElementById('archivBtn').onclick=async()=>{
if(d&&d.ok){
let text=` ${d.anzahl} Anruf(e) archiviert (simuliert)`;
if(d.export_anzahl)text+=` · ${d.export_anzahl} bewertete Anrufe exportiert`;
if(d.log_archiviert)text+=' · Verlauf gesichert & geleert';
toast(text);takt();
} else{toast('Archivieren fehlgeschlagen.')}
};