Drei unabhaengige Schutzschichten gegen falsche Umschreibungen
(ae/oe/ue/ss statt ä/ö/ü/ß) im Lagebild:
1. Prompt-Ergaenzung in INCREMENTAL_ANALYSIS_PROMPT_TEMPLATE und
INCREMENTAL_BRIEFING_PROMPT_TEMPLATE (analyzer.py): explizite
Priorisierung, dass die Regel "echte UTF-8-Umlaute" Vorrang vor
"bestehende Formulierungen beibehalten" hat. Adressiert den Fall,
dass Claude beim inkrementellen Update Altlasten weitertraegt.
2. Deterministische Normalisierung in post_refresh_qc.py:
- normalize_german_umlauts(text) - Regex mit Wortgrenzen, case-
preserving, Whitelist-tauglich, ~140 Eintraege im Woerterbuch
abgeleitet aus den 140 Hard-Hits in Lage #6
- normalize_umlaut_fields(db, incident_id) - laedt summary und
latest_developments, normalisiert, schreibt nur bei Aenderungen
zurueck (idempotent)
- Eingehaengt in run_post_refresh_qc() nach dem Location-Check,
Fehler stoppen die Pipeline nicht (identisches Muster wie
bestehende Checks)
3. scripts/bootstrap_umlaut_repair.py - Einmal-Skript zur
Bestandsbereinigung der bereits gespeicherten summary-Felder.
Idempotent. Beim initialen Lauf auf Produktiv-DB: 14 Lagen
aktualisiert, 431 Ersetzungen insgesamt, Lage #6 von 140 auf
15 Rest-Treffer reduziert.
Whitelist (leer): aktuell kein Konflikt zwischen deutschen Ziel-
Woertern und englischen Fremdwoertern. Kann bei Bedarf erweitert
werden ohne Schema-Aenderung.
Verifikation:
- py_compile OK fuer alle drei Dateien
- Service-Restart ohne Errors
- Unit-Tests: positive Faelle ("Oeffnung der Strasse" -> 4 Ersetzungen),
Whitelist ("Boeing liefert Business-Access" -> 0 Ersetzungen),
Komposita ("Wasserstrasse", "Parlamentspraesident") korrekt
- Bootstrap 2x ausgefuehrt (erster Lauf 288 Ersetzungen, zweiter 143
nach Dict-Erweiterung), kumulativ 431
Architektur bleibt dormant ohne Daten-Altlasten: wenn keine Lage
Umschreibungen enthaelt, arbeitet normalize_umlaut_fields in <1ms
und schreibt nichts. Kein Overhead im Refresh-Pfad.
79 Zeilen
2.4 KiB
Python
79 Zeilen
2.4 KiB
Python
"""Einmal-Repair: normalisiert Umlaute in summary und latest_developments
|
|
aller aktiven Lagen deterministisch (deutsche Umschreibungs-Form -> echte Umlaute).
|
|
|
|
Idempotent: mehrfaches Ausfuehren hat keinen zusaetzlichen Effekt, wenn
|
|
bereits normalisierte Texte vorliegen.
|
|
|
|
Aufruf (auf dem Monitor-Server):
|
|
cd /home/claude-dev/AegisSight-Monitor/src
|
|
python3 ../scripts/bootstrap_umlaut_repair.py
|
|
"""
|
|
import sqlite3
|
|
import sys
|
|
import os
|
|
|
|
# Sicherstellen, dass src/ im PYTHONPATH ist, damit services/post_refresh_qc importiert werden kann
|
|
_here = os.path.dirname(os.path.abspath(__file__))
|
|
_src = os.path.abspath(os.path.join(_here, "..", "src"))
|
|
if _src not in sys.path:
|
|
sys.path.insert(0, _src)
|
|
|
|
from services.post_refresh_qc import normalize_german_umlauts # noqa: E402
|
|
|
|
DB_PATH = "/home/claude-dev/osint-data/osint.db"
|
|
|
|
|
|
def main():
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
try:
|
|
c = conn.cursor()
|
|
rows = c.execute(
|
|
"SELECT id, title, summary, latest_developments FROM incidents "
|
|
"WHERE status IN ('active', 'archived') ORDER BY id"
|
|
).fetchall()
|
|
|
|
total_summary = 0
|
|
total_dev = 0
|
|
updated = 0
|
|
|
|
for r in rows:
|
|
iid = r["id"]
|
|
title = r["title"] or ""
|
|
summary_orig = r["summary"] or ""
|
|
dev_orig = r["latest_developments"] or ""
|
|
|
|
new_summary, n_s = normalize_german_umlauts(summary_orig)
|
|
new_dev, n_d = normalize_german_umlauts(dev_orig)
|
|
|
|
if n_s == 0 and n_d == 0:
|
|
continue
|
|
|
|
c.execute(
|
|
"UPDATE incidents SET summary = ?, latest_developments = ? WHERE id = ?",
|
|
(
|
|
new_summary if n_s > 0 else summary_orig,
|
|
new_dev if n_d > 0 else dev_orig,
|
|
iid,
|
|
),
|
|
)
|
|
updated += 1
|
|
total_summary += n_s
|
|
total_dev += n_d
|
|
print(
|
|
f" Lage #{iid:>3} {title[:50]:50} "
|
|
f"summary: {n_s:>4} | latest_developments: {n_d:>3}"
|
|
)
|
|
|
|
conn.commit()
|
|
print()
|
|
print(f"Ergebnis: {updated} Lagen aktualisiert. "
|
|
f"{total_summary} Ersetzungen in summary, {total_dev} in latest_developments "
|
|
f"(gesamt {total_summary + total_dev}).")
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|