2026-10-18 15:14:18 +02:00
|
|
|
# talk
|
|
|
|
|
|
|
|
|
|
> **Status: WIP** — aktive Entwicklung (talk 2.0). Binde Spezifikation:
|
|
|
|
|
> [`.scratch/talk-2-0/spec.md`](.scratch/talk-2-0/spec.md) ·
|
|
|
|
|
> Implementierungsplan: [`.scratch/talk-2-0/plan.md`](.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`.
|
|
|
|
|
|
2026-10-18 15:39:49 +02:00
|
|
|
**Hinweis:** In diesem Stand ist `say` (und der Default-Aufruf
|
2026-10-18 16:34:54 +02:00
|
|
|
`talk "Text"`) implementiert — inklusive der kompletten Provider-Kette
|
|
|
|
|
(ElevenLabs → OpenAI → Edge-TTS → OS-Stimme, blockierend;
|
2026-10-18 15:39:49 +02:00
|
|
|
Daemon-Anbindung folgt). Alle anderen Befehle sind Stubs und melden
|
|
|
|
|
`not implemented yet` (Exit-Code ≠ 0).
|
|
|
|
|
|
2026-10-18 16:34:54 +02:00
|
|
|
### 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:
|
|
|
|
|
|
|
|
|
|
```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).
|
|
|
|
|
|
2026-10-18 15:39:49 +02:00
|
|
|
### 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.
|
2026-10-18 15:14:18 +02:00
|
|
|
|
|
|
|
|
## Entwicklung
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
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](LICENSE).
|