mirror of
https://github.com/Jeuners/Logpy-AgentOne.git
synced 2026-09-09 15:02:33 +02:00
Praxis-Telefon-Agent: Anrufannahme, Transkription, Triage — vollständig on-prem
Nimmt Anrufe einer Hausarztpraxis entgegen, transkribiert sie lokal, kategorisiert das Anliegen und legt es strukturiert ab. Keine Patientendaten verlassen den Rechner: Spracherkennung, Sprachmodell und Sprachsynthese laufen lokal, im Datenpfad steht kein Cloud-Dienst. Aufbau: - FreeSWITCH nimmt über einen SIP-Trunk an, spielt die Ansage und nimmt auf. - pipe.watch erkennt fertige Aufnahmen und schiebt sie durch die Pipe. - whisper.cpp transkribiert, ein lokales Sprachmodell (Ollama) ordnet in Kategorie und Dringlichkeit ein — mit erzwungenem JSON-Schema. - Ablage lokal, optional Nextcloud (WebDAV) und ein Deck-Board. - Leitstand (pipe.server): Board mit Eingang/In Bearbeitung/Rückfragen/Erledigt, Aufnahmen zum Anhören, Verlauf und Ampeln für alle beteiligten Dienste. Zugangsdaten und Anrufdaten liegen außerhalb des Repositorys (.env, ablage/, telefon/). Konfiguration siehe .env.example, Einrichtung siehe README.
This commit is contained in:
commit
1a1280e79d
24 changed files with 2253 additions and 0 deletions
108
telefon/starten.sh
Executable file
108
telefon/starten.sh
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
#!/bin/bash
|
||||
# Startet die Telefonannahme: FreeSWITCH nimmt Anrufe an, pipe.watch verarbeitet
|
||||
# die Aufnahmen. Prueft vorher, was erfahrungsgemaess schiefgeht.
|
||||
set -uo pipefail
|
||||
PROJEKT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$PROJEKT"
|
||||
|
||||
fehler=0
|
||||
melde() { printf ' %-38s %s\n' "$1" "$2"; }
|
||||
|
||||
echo "Vorabpruefung"
|
||||
|
||||
# Ollama - ohne Kategorisierung bleibt jeder Anruf liegen.
|
||||
if curl -s --max-time 5 "${OLLAMA_URL:-http://127.0.0.1:11434}/api/version" >/dev/null 2>&1; then
|
||||
melde "Ollama" "laeuft"
|
||||
else
|
||||
melde "Ollama" "FEHLT - 'ollama serve &' starten"; fehler=1
|
||||
fi
|
||||
|
||||
# Ansage
|
||||
if [ -f telefon/ansage.wav ]; then
|
||||
melde "Ansage" "$(ffprobe -v error -show_entries format=duration -of csv=p=0 telefon/ansage.wav | cut -c1-4) s"
|
||||
else
|
||||
melde "Ansage" "FEHLT - telefon/ansage_bauen.sh ausfuehren"; fehler=1
|
||||
fi
|
||||
|
||||
# Trunk-Konfiguration
|
||||
FS_ETC="${FS_ETC:-/opt/homebrew/etc/freeswitch}"
|
||||
FS_PORT="${FS_PORT:-8099}" # Event-Socket; 8021 ist auf diesem Mac belegt
|
||||
if [ -f "$FS_ETC/sip_profiles/external/plusnet.xml" ]; then
|
||||
melde "Trunk-Konfiguration" "eingerichtet"
|
||||
else
|
||||
melde "Trunk-Konfiguration" "FEHLT - telefon/freeswitch/einrichten.sh"; fehler=1
|
||||
fi
|
||||
|
||||
# Telephone.app streitet sich mit uns um dieselbe SIP-Registrierung.
|
||||
if pgrep -xq Telephone; then
|
||||
melde "Telephone.app" "LAEUFT - beenden, sonst Registrierungskonflikt"; fehler=1
|
||||
else
|
||||
melde "Telephone.app" "beendet"
|
||||
fi
|
||||
|
||||
[ $fehler -eq 0 ] || { echo; echo "Abbruch - erst die Punkte oben klaeren."; exit 1; }
|
||||
|
||||
echo
|
||||
if pgrep -xq freeswitch; then
|
||||
echo "FreeSWITCH laeuft bereits."
|
||||
else
|
||||
echo "Starte FreeSWITCH ..."
|
||||
# -conf ist noetig: FreeSWITCH liest sonst aus dem Cellar-Verzeichnis, das
|
||||
# jedes Homebrew-Upgrade ueberschreibt. $FS_ETC bleibt bestehen.
|
||||
# -rp: Echtzeit-Priorität. Auf einem Rechner, der nebenher Whisper und ein
|
||||
# Sprachmodell laufen lässt, kommt FreeSWITCH sonst nicht rechtzeitig dran und
|
||||
# das Audio stückelt - RTP will alle 20 ms ein Paket losschicken.
|
||||
freeswitch -nc -rp -nonatmap \
|
||||
-conf "$FS_ETC" \
|
||||
-log /opt/homebrew/var/log/freeswitch \
|
||||
-db /opt/homebrew/var/lib/freeswitch/db \
|
||||
-run /opt/homebrew/var/run/freeswitch
|
||||
# FreeSWITCH braucht nach dem Backgrounding ~40 s, bis Sofia die Profile hat.
|
||||
sleep 15
|
||||
fi
|
||||
|
||||
# Auf die Registrierung beim Provider warten.
|
||||
# Quelle ist fs_cli, nicht das Log: das Log wird zum Testen geleert und taugt
|
||||
# dann nicht mehr als Zustandsquelle.
|
||||
echo -n "Warte auf Trunk-Registrierung "
|
||||
status=""
|
||||
for i in $(seq 1 30); do
|
||||
wert=$(fs_cli -P "$FS_PORT" -x "sofia status gateway plusnet" 2>/dev/null \
|
||||
| awk '/^Status/{print $2}')
|
||||
case "$wert" in
|
||||
UP) status="UP"; break ;;
|
||||
DOWN) : ;; # noch im Aufbau, weiter warten
|
||||
esac
|
||||
echo -n "."; sleep 2
|
||||
done
|
||||
echo
|
||||
fs_cli -P "$FS_PORT" -x "sofia status gateway plusnet" 2>/dev/null \
|
||||
| grep -E '^(Name|State|Status)' || echo " (fs_cli antwortet nicht)"
|
||||
|
||||
if [ "${status:-}" = "UP" ]; then
|
||||
# Watcher und Leitstand mitstarten, falls sie nicht schon laufen.
|
||||
if pgrep -f "[p]ipe.watch" >/dev/null; then
|
||||
echo "Verarbeitung laeuft bereits."
|
||||
else
|
||||
# nice 10: Transkription und Kategorisierung dürfen warten, ein laufendes
|
||||
# Telefonat nicht. Auf 16 GB RAM konkurrieren beide sonst um die Maschine.
|
||||
nohup nice -n 10 python3 -u -m pipe.watch > telefon/watcher.log 2>&1 &
|
||||
echo "Verarbeitung gestartet (Log: telefon/watcher.log)"
|
||||
fi
|
||||
if pgrep -f "[p]ipe.server" >/dev/null; then
|
||||
echo "Leitstand laeuft bereits."
|
||||
else
|
||||
nohup python3 -u -m pipe.server > telefon/leitstand.log 2>&1 &
|
||||
sleep 2
|
||||
head -1 telefon/leitstand.log
|
||||
fi
|
||||
sleep 2
|
||||
echo
|
||||
ip=$(ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null)
|
||||
echo "Bereit. Leitstand: http://${ip:-127.0.0.1}:${LEITSTAND_PORT:-8088}"
|
||||
else
|
||||
echo
|
||||
echo "Trunk ist NICHT registriert. Log:"
|
||||
echo " tail -f /opt/homebrew/var/log/freeswitch/freeswitch.log"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue