feat: Branchen-Profile - Projekt fuer andere Einsatzzwecke konfigurierbar machen

Kategorien, Prompt und Notfall-Sicherheitsnetz waren fest auf eine
Hausarztpraxis zugeschnitten (categorize.py: KATEGORIEN-Liste, _NOTFALL_MUSTER-
Regex). Fuer einen anderen Einsatzzweck (z.B. 24h-Aufzug-Notdienst) musste
bisher Python-Code geaendert werden.

Neu: profile/<name>/ buendelt prompt.txt, kategorien.json, sicherheitsnetz.txt
und ansage.txt - alles, was fachlich vom Einsatzzweck abhaengt, an einer
Stelle. PROFIL in der .env waehlt den aktiven Ordner (Default "praxis", altes
Verhalten bleibt exakt gleich - per Test verifiziert: identische Kategorien-
Liste und Sicherheitsnetz-Muster). profile/aufzug-notdienst/ liegt als
ausformuliertes Beispielprofil bei (eigene Kategorien, eigenes
Sicherheitsnetz, eigene Ansage).

Dringlichkeitsstufen (niedrig/normal/hoch/notfall) bleiben bewusst fest -
nur die Kategorien sind einsatzzweck-spezifisch. Neues pipe/kategorien.py
laedt das Profil-Schema einmal fuer categorize.py, dashboard.py, deck.py und
server.py (Leitstand-JS: Kategorie-Label kommen jetzt vom Server statt fest
im Frontend zu stehen).

prompts/categorize_de.txt und telefon/ansage.txt sind nach profile/praxis/
umgezogen (git erkennt es als Rename).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EbdWYnDtyMgxsq4eN1WnrQ
This commit is contained in:
Jeuner 2026-08-28 17:07:29 +02:00
parent d39b360b7b
commit 87621e5bec
17 changed files with 277 additions and 70 deletions

View file

@ -1 +0,0 @@
Guten Tag, hier ist die Demo Praxis. Alle Kollegen befinden sich im Gespräch. Bitte hinterlassen Sie ihr Anliegen nach dem Signal. Wir rufen Sie zurück.

View file

@ -1,5 +1,6 @@
#!/bin/bash
# Erzeugt die Telefonansage aus telefon/ansage.txt.
# Erzeugt die Telefonansage aus profile/$PROFIL/ansage.txt (Branchen-Profil,
# siehe README).
# Ergebnis: telefon/ansage.wav in Telefonqualitaet (8 kHz mono, PCM16).
#
# Drei Sprachsynthesen:
@ -10,6 +11,7 @@
# wiederverwendet, es geht dabei keine Patientendaten raus)
#
# Steuerung ueber Umgebungsvariablen bzw. .env:
# PROFIL=<Ordnername unter profile/, Default "praxis">
# ANSAGE_TTS=piper|say|mistral
# ANSAGE_STIMME=<Piper-Modellname, say-Stimme, oder Voxtral-Stimmen-Slug>
# ANSAGE_EMOTION=<Sprecher-ID, nur bei thorsten_emotional: 0=amused,
@ -32,6 +34,10 @@ if [ -f .env ]; then
done < .env
fi
PROFIL="${PROFIL:-praxis}"
ANSAGE_TXT="profile/$PROFIL/ansage.txt"
[ -f "$ANSAGE_TXT" ] || { echo "Ansage-Text fehlt: $ANSAGE_TXT (PROFIL=$PROFIL)" >&2; exit 1; }
STIMMEN_ORDNER="${PIPER_STIMMEN:-$HOME/piper-voices}"
STIMME="${ANSAGE_STIMME:-de_DE-thorsten_emotional-medium}"
EMOTION="${ANSAGE_EMOTION:-0}"
@ -53,7 +59,7 @@ case "$TTS" in
piper)
MODELL="$STIMMEN_ORDNER/$STIMME.onnx"
[ -f "$MODELL" ] || { echo "Piper-Stimme fehlt: $MODELL" >&2; exit 1; }
tr '\n' ' ' < telefon/ansage.txt \
tr '\n' ' ' < "$ANSAGE_TXT" \
| python3 -m piper -m "$MODELL" -s "$EMOTION" --length-scale "$TEMPO" \
-f "$TMP/sprache_roh.wav"
ffmpeg -v error -y -i "$TMP/sprache_roh.wav" -ar 8000 -ac 1 "$TMP/sprache.wav"
@ -61,7 +67,7 @@ case "$TTS" in
;;
say)
SAY_STIMME="${ANSAGE_STIMME:-Anna}"
say -v "$SAY_STIMME" -r 180 -f telefon/ansage.txt -o "$TMP/sprache.aiff"
say -v "$SAY_STIMME" -r 180 -f "$ANSAGE_TXT" -o "$TMP/sprache.aiff"
ffmpeg -v error -y -i "$TMP/sprache.aiff" -ar 8000 -ac 1 "$TMP/sprache.wav"
BESCHREIBUNG="say/$SAY_STIMME"
;;
@ -69,7 +75,7 @@ case "$TTS" in
MISTRAL_STIMME="${ANSAGE_STIMME:-en_paul_neutral}"
MISTRAL_MODELL="${MISTRAL_TTS_MODEL:-voxtral-mini-tts-latest}"
[ -n "${MISTRAL_KEY:-}" ] || { echo "MISTRAL_KEY fehlt (ANSAGE_TTS=mistral)" >&2; exit 1; }
TEXT="$(tr '\n' ' ' < telefon/ansage.txt)"
TEXT="$(tr '\n' ' ' < "$ANSAGE_TXT")"
PAYLOAD="$(TTS_MODEL="$MISTRAL_MODELL" TTS_VOICE="$MISTRAL_STIMME" python3 -c '
import json, os, sys
print(json.dumps({