feat: Kontakt-Abgleich gegen Nextcloud-Adressbuch bei eingehenden Anrufen

pipe/kontakte.py: CardDAV-Abgleich (stdlib urllib, gleicher Stil wie
store.py) gegen ein konfigurierbares Adressbuch (NEXTCLOUD_ADRESSBUCH,
Default "contacts"). Rufnummer wird normalisiert (+49/0049/0-Schreibweisen,
Leerzeichen/Bindestriche), Adressbuch 5 Minuten gecacht statt pro Anruf neu
geladen. Ohne Nextcloud-Konfiguration oder bei Ausfall: sauber None, kein
Anruf bricht deswegen ab.

process_call.py speichert den Treffer als "bekannter_kontakt" in meta.json;
server.py zeigt ihn als gruenen Badge neben der Rufnummer im Board - fuer den
Abgleich "Anrufer sagt X, Nummer gehoert laut Adressbuch Y" auf einen Blick.

Nextcloud-Zugangsdaten aktivierten bisher automatisch auch den Datei-Upload
(store.hochladen) - fuer den reinen Kontakt-Abgleich waere das ein unge-
wollter Nebeneffekt, der das "Vollstaendig on-prem"-Versprechen des Projekts
bricht. Neuer Schalter NEXTCLOUD_UPLOAD (Default an, bestehende Installa-
tionen unveraendert) trennt beides.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PuP3zfgYqhnrwyEne2ejG7
This commit is contained in:
Jeuner 2026-08-23 02:18:51 +02:00
parent f77bc6e558
commit 08ca806cda
6 changed files with 159 additions and 3 deletions

View file

@ -12,7 +12,7 @@ import argparse
import sys
from datetime import datetime
from . import categorize, protokoll, store, transcribe
from . import categorize, kontakte, protokoll, store, transcribe
def verarbeite(audio: str, anrufer_nummer: str | None = None,
@ -37,6 +37,13 @@ def verarbeite(audio: str, anrufer_nummer: str | None = None,
nummer=anrufer_nummer, kategorie=auswertung["kategorie"],
dringlichkeit=auswertung["dringlichkeit"])
bekannter_kontakt = kontakte.nachschlagen(anrufer_nummer)
if bekannter_kontakt:
print(f" Kontakt: bekannt als »{bekannter_kontakt['name']}« "
f"({bekannter_kontakt['adressbuch']})")
protokoll.schreibe("kontakt", f"bekannter Anrufer: {bekannter_kontakt['name']}",
nummer=anrufer_nummer)
datensatz = {
"empfangen": empfangen.isoformat(timespec="seconds"),
"anrufer_nummer": anrufer_nummer,
@ -44,6 +51,7 @@ def verarbeite(audio: str, anrufer_nummer: str | None = None,
"erkannte_sprache": t.sprache,
"audio_dauer_s": t.dauer,
"auswertung": auswertung,
"bekannter_kontakt": bekannter_kontakt,
}
print("▸ Lege ab …")