Stimmen werden jetzt lazy pro Name geladen und gecacht statt einer fest verdrahteten Default-Stimme; das UI bekommt ein Dropdown mit allen 26 deutschen Pocket-TTS-Stimmen (/api/voices), Auswahl wird im Browser gemerkt und ist während eines laufenden Gesprächs gesperrt. Zusätzlich ein optionaler ASTRA_TAILNET_HOST, damit die App über `tailscale serve` auch von einem anderen Gerät im selben Tailnet erreichbar ist, ohne die Loopback-only-Härtung für alle anderen Hosts aufzuweichen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVgSHNHdRx3UNTBodFmhRA
2.9 KiB
astra
Ein lokaler deutscher Sprachagent für Apple Silicon. Kein Cloud-Anruf, kein Tracking, kein gespeichertes Audio — Spracherkennung, Sprachmodell und Sprachausgabe laufen alle auf deinem Mac.
Wie es funktioniert
Drei lokale Modelle, verbunden über eine Pipecat-Pipeline:
| Stufe | Modell | Wo |
|---|---|---|
| Spracherkennung | Nemotron ASR (streaming) | MLX, on-device |
| Sprachmodell | Qwen 3.5 | über natives Ollama /api/chat |
| Sprachausgabe | Pocket TTS, 26 deutsche Stimmen wählbar | MLX, on-device |
Der Browser spricht per WebRTC direkt mit einem FastAPI-Server auf
localhost:7860. Der Server ist bewusst nur lokal erreichbar: Host- und
Origin-Prüfung auf jedem Request, strikte Content-Security-Policy, keine
offenen Ports nach außen.
Die Stimme lässt sich im UI per Dropdown wählen (/api/voices listet alle
26, Auswahl wird im Browser gemerkt). Jede Stimme wird beim ersten Gebrauch
lazy geladen und danach für die Laufzeit des Prozesses gecacht.
Starten
uv sync
uv run python -m astra.prepare # lädt & prüft alle drei Modelle einmalig
uv run python -m astra.server # startet auf http://localhost:7860
Ollama muss separat laufen (ollama serve) und qwen3.5:latest muss
gezogen sein. Die Seite öffnen, Mikrofon erlauben, sprechen.
Konfiguration
Über Umgebungsvariablen, siehe astra/core.py::Settings:
| Variable | Default |
|---|---|
ASTRA_MODEL |
qwen3.5:latest |
ASTRA_OLLAMA_URL |
http://127.0.0.1:11434 |
ASTRA_STT_MODEL |
mlx-community/nemotron-3.5-asr-streaming-0.6b-8bit |
ASTRA_TTS_LANGUAGE |
german |
ASTRA_VOICE |
alba |
ASTRA_PORT |
7860 |
ASTRA_TAILNET_HOST |
(leer) — z. B. minim4-1.tail0f2cb2.ts.net |
Tests
uv run pytest
uv run ruff check .
Im Tailnet freigeben
Standardmäßig nur localhost erreichbar. Für Zugriff von einem anderen
Gerät im selben Tailscale-Netz:
tailscale serve --bg 7860
ASTRA_TAILNET_HOST="$(tailscale status --json | python3 -c 'import json,sys;print(json.load(sys.stdin)["Self"]["DNSName"].rstrip("."))')" \
uv run python -m astra.server
Danach ist die Seite unter https://<tailnet-host>/ erreichbar (Port 443,
implizit — Tailscale terminiert TLS und proxyt auf 7860). Host- und
Origin-Prüfung lassen dann zusätzlich diesen einen Hostnamen durch.
Sicherheit
- Nur
localhost/127.0.0.1(bzw. der optionale Tailnet-Host) erreichbar, alle anderen Hosts bekommen 403 - POST-Requests werden gegen den erwarteten Origin geprüft
thinkist im Ollama-Request hart auffalsegesetzt — die Pipeline wirft, falls das Modell trotzdem Denkausgabe liefert- Kein Audio, keine Transkripte werden auf Disk geschrieben; der Gesprächsverlauf lebt nur im Speicher der laufenden Session
Erstellt von Astra (Grunddeploy), gecheckt, dokumentiert und bewertet durch Claude.