m3ta-chiron b20e6dd319 feat(config): Gesetz-Felder rate_limit, allow_high_burst, quiet_hours, quiet_mode
Queue-Section ([queue] rate_limit = "30s", allow_high_burst = true) und
Ruhezeiten (quiet_hours = "18:00-08:00" lokal über Mitternacht,
quiet_mode = discard|toast) mit Env-Overrides TALK_RATE_LIMIT,
TALK_ALLOW_HIGH_BURST, TALK_QUIET_HOURS ("off" = aus), TALK_QUIET_MODE.
Default: 1 Ansage / 30 s, Burst an, Ruhezeit aus (Opt-in wie Mute —
ein Uhrzeit-Gesetz als Default würde jeden Cron in den Abendstunden
stilllegen). Validierung gegen queue.ParseQuietHours als eine Quelle;
partielle [queue]-Tabellen behalten Defaults (tischgetestet).
2026-10-18 17:40:35 +02:00

talk

Status: WIP — aktive Entwicklung (talk 2.0). Binde Spezifikation: .scratch/talk-2-0/spec.md · Implementierungsplan: .scratch/talk-2-0/plan.md

talk macht Skripte und KI-Agenten hörbar: Ein Aufruf — talk "Build fertig" — spricht eine kurze Nachricht über eine TTS-Provider-Kette (ElevenLabs → OpenAI → Edge-TTS → OS-Stimme), serialisiert durch den Daemon talkd. Cross-platform (Windows/macOS/Linux, amd64/arm64), statische Binaries, keine Runtime-Abhängigkeiten.

Befehle

Befehl Zweck
talk "Text" Ansage — Abkürzung für talk say, non-blocking
talk say "Text" Ansage (Text als Argument oder von stdin)
talk wrap -- <Befehl> Befehl ausführen, Erfolg/Misserfolg + Dauer ansagen
talk mute / talk unmute Ansagen dauerhaft stummschalten / Stummschaltung aufheben
talk status Daemon-Status (Queue, Mute, Provider, Version)
talk cancel laufende und geplante Ansagen abbrechen
talk voices verfügbare Stimmen anzeigen
talk test Test-Ansage ausgeben
talk doctor Selbstdiagnose des Setups
talk setup geführte Ersteinrichtung (Wizard)

Say-Flags (gelten auch für talk "Text"): --wait, --now, --priority, --voice, --lang, --provider.

Hinweis: In diesem Stand sind implementiert: say (und talk "Text") mit der kompletten Provider-Kette und Daemon-Anbindung (non-blocking über talkd, siehe unten), mute, unmute, status, cancel. Die übrigen Befehle sind Stubs und melden not implemented yet (Exit-Code ≠ 0).

Daemon talkd (Task 04)

talkd besitzt die Ansage-Queue und spricht seriell ab — genau eine Ansage gleichzeitig, Reihenfolge now > high > normal > low (FIFO je Level). Der HTTP-Server lauscht nur auf 127.0.0.1; Port: Default 7800, config [server] port, Env TALK_PORT (schlagen den Default).

Endpunkt Wirkung
POST /speak {text, priority?, provider?, voice?, lang?, now?} → 202 {"id":"…"}; bei Mute: 202 {"id":"","muted":true} (Ansage verworfen — dokumentiertes Verhalten)
GET /status {"version", "queue", "queue_ids", "current", "muted", "provider"}
POST /cancel bricht die laufende Ansage ab + leert die Queue → 200 {"cancelled":n}
POST /mute / POST /unmute persistenter Mute-State → 200 {"muted":bool}
  • CLI-Verhalten: talk say (und talk "Text") erkennt den Daemon via GET /status. Läuft er: enqueue + sofortige Rückkehr (non-blocking, stdout erhält die Item-ID); --wait pollt bis zur Fertigstellung; --now springt vor die Warteschlange; bei Mute sagt die CLI muted. talk mute/unmute/status/cancel sind Daemon-Aufrufe mit plain Output.
  • Mute ist persistent (Datei mute im Config-Dir, Inhalt true/ false) und überlebt Daemon-Restarts. talk mute ohne laufenden Daemon schreibt die Datei direkt — der Daemon liest sie bei jeder Ansage neu, der Zustand greift also auch offline.
  • Degraded Mode: Antwortet kein Daemon, spielt talk lokal und sequenziell weiter — serialisiert über die Lock-Datei talk.lock im Config-Dir (Kollision = warten; verwaisste Locks gelten nach 60 s als verfallen). Mute wird auch hier respektiert. Nichts bricht still.
  • Rate-Limit und Ruhezeiten folgen in Task 05; die Rate-Limit-Struktur existiert bereits (internal/queue), ist in diesem Stand aber bewusst noch nicht angebunden (Default: unbegrenzt).

Provider-Kette (Task 03)

Ohne Pin läuft die Vier-Stufen-Fallback-Kette ElevenLabs → OpenAI TTS → Edge-TTS → OS built-in: Bei fehlendem Key, HTTP-Fehler, Timeout oder Netz-Problem fällt die Kette automatisch auf die nächste Stufe; jeder Fallback wird auf stderr protokolliert (nie still). Pinnen per --provider=<name> oder provider = "<name>" in der config.toml.

Stufe Key (Env) Default-Endpunkt Audio
elevenlabs TALK_ELEVENLABS_KEY https://api.elevenlabs.io mp3
openai TALK_OPENAI_KEY https://api.openai.com mp3
edge — (kostenlos) wss://speech.platform.bing.com/... mp3
osbuiltin — lokale OS-TTS WAV/PCM

Keys laufen ausschließlich über Env-Variablen (nie in die config.toml). Endpunkte sind konfigurierbar — Datei [providers.<name>] endpoint = "…" bzw. Env TALK_ELEVENLABS_ENDPOINT / TALK_OPENAI_ENDPOINT / TALK_EDGE_ENDPOINT (Env schlägt Datei; so zeigen Tests/CI die Kette auf Fake-Server). Das OpenAI-Modell ist konfigurierbar ([providers.openai] model, Default tts-1).

Stimmen: neutralen Repo-Defaults je Provider+Sprache (ElevenLabs „Rachel", OpenAI „alloy", Edge de-DE-KatjaNeural/en-US-AriaNeural) kann man pro Sprache überordnen — config.toml:

[voice.elevenlabs]
de = "21m00Tcm4TlvDq8ikWAM"   # eigene Stimme je Sprache
en = "21m00Tcm4TlvDq8ikWAM"

[voice.edge]
de = "de-DE-KatjaNeural"

Rangfolge: --voice-Flag > voice.<provider>.<lang> > Repo-Default. MP3 wird von der Binärdatei selbst dekodiert (reiner Go-Dekoder, kein ffmpeg, CGO-frei).

OS-TTS auf Linux (Dev-Abhängigkeit espeak)

Der OS-Provider osbuiltin nutzt auf Linux zwei Wege:

  • Audio-Bytes (Wiedergabe über den eingebauten oto-Sink): benötigt espeak (oder espeak-ng). Auf NixOS als Dev-Abhängigkeit: nix shell nixpkgs#espeak-ng.
  • Direktansage ohne espeak: spd-say (speech-dispatcher) — spielt selbst über den Daemon ab, kann aber nach spd-say --help keine Bytes in Dateien/Pipes liefern. talk nutzt diesen Weg automatisch, wenn kein espeak vorhanden ist.

TALK_AUDIO_SINK=null (oder audio.sink = "null" in der config.toml) schaltet jede Tongabe ab — für CI und Server.

Entwicklung

go build ./...   # bauen
go test ./...    # Tests
go vet ./...     # statische Analyse
gofmt -l .       # Formatierung prüfen (leerer Output = ok)

CI: .gitea/workflows/test.yml (Gitea Actions) läuft vet, gofmt-Check, Tests und Build bei jedem Push und Pull Request.

Lizenz

MIT — siehe LICENSE.

S
Description
No description provided
Readme MIT
816 KiB
0 Stars 1 Watchers 0 Forks
talk v0.1.1
Latest
2026-10-25 12:59:59 +01:00
Languages
Go 99.3%
Nix 0.5%
Shell 0.2%