Commit Graph
6 Commits
Author SHA1 Message Date
m3ta-chironandClaude Fable 5.1 85fa64cfe6 refactor: switch the whole project to English
talk is going to be published. Code comments, CLI output, error messages,
daemon log lines, MCP descriptions and results, test names and assertions,
README, spec, skill, build scripts and flake are now English. Only the
spoken announcement texts stay bilingual: the wrap result and the test
sentence are German or English depending on the detected language.

Language fallback is now configurable: `lang = "en" | "de"` (env
TALK_LANG, default en) is used when detection cannot tell (numbers, single
words, ties) and for talk's own announcements. langdetect.Detect takes the
fallback as an argument instead of hard-coding German. `talk setup` asks for
it; `talk doctor` and `talk status` show it.

Vocabulary pinned across packages so the process-boundary tests observe
stable strings: chain log lines ("chain: tier X skipped (not available)",
"falling back to the next tier", "spoken via X"), queue lines ("discarded:
quiet hours ... active", "replaced by toast", "max_age"), CLI notes
("speaking directly", "daemon started at", "no daemon", "nothing to cancel"),
status block with aligned English labels, MCP messages, origin guard 403.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 11:15:35 +02:00
m3ta-chironandClaude Fable 5.1 df9a9b30cf feat(cli): doctor, test, voices, setup — Einrichtung und Diagnose ohne TUI
Usability-Schicht für Nutzer, die kein Terminal-Handbuch lesen wollen:

- `talk doctor`: eine Zeile je Prüfpunkt mit klarem Satz, was Sache ist und
  was zu tun wäre — Config (kaputt → ✘, die übrigen Prüfungen laufen mit
  Defaults weiter), Daemon (läuft / startet beim nächsten Sprechbefehl /
  fremder Dienst auf dem Port → ✘ mit Port-Hinweis), Audio (oto-Kontext
  wirklich initialisieren; null → ⚠), jede Provider-Stufe (Key-Env-Name,
  Endpunkt, Default-Stimme; OS-Stimme nennt den gefundenen Mechanismus),
  Mute (an → ⚠ mit unmute-Hinweis), Gesetze inkl. gerade aktiver Ruhezeit.
  --probe macht echte Synthese-Proben, --json liefert die Liste. Exit 0
  ohne ✘. Windows-Konsolen bekommen [OK]/[WARN]/[FAIL].
- `talk test`: Testsatz direkt über den Sprech-Kern (nicht über den
  Daemon), nennt die Stufe, die wirklich gesprochen hat, Synthese- und
  Wiedergabezeit; Mute/Ruhezeit gelten bewusst nicht, Mute wird genannt.
- `talk voices`: kuratierter Katalog mit Namen (ElevenLabs-Premade, OpenAI,
  Edge-Neural de/en-Locales) als Tabelle, „*“ = effektive Default-Stimme
  (Config vor Repo-Default), Config-IDs außerhalb des Katalogs als eigene
  Zeile, Filter --provider/--lang, --json.
- `talk setup`: wenige Fragen statt Bubble Tea — Keys nur als Hinweis
  (ohne Key läuft die Edge-Stimme), Stimme je Sprache aus dem Katalog mit
  Probehören, Ruhezeit; schreibt die config.toml zusammengeführt mit
  bestehenden Werten (.bak), spricht einen Testsatz. q bricht ab, bevor
  etwas geschrieben wird; ohne Terminal keine Fragen, nur die wirksame
  Konfiguration.

Unterbau: provider.Catalog/VoiceName/DefaultVoice, Chain.SpeakOutcome
(Stufe, Bytes, Zeiten) durch speak.Engine bis in Daemon-Log und test,
audio.Check (oto-Initialisierung ohne Ton), config.Path,
OSBuiltin.Describe. README: Abschnitt „Erste Schritte“.

Tests: voices-Zeilen (Default-Markierung, Config-Override, Filter, JSON),
doctor (ohne Daemon, Mute/Key via JSON, fremder Dienst → Exit 1, kaputte
Config → ✘ aber vollständiger Bericht), test (fake espeak), setup
(stdin-Antworten → config.toml-Inhalt, Merge mit .bak, Abbruch schreibt
nichts, Pipe stellt keine Fragen), Prozessgrenze: doctor/--probe/voices/
test gegen echten Daemon.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 10:08:44 +02:00
m3ta-chiron 3b44605234 fix(provider): Chain.Speak läuft im Direkt-Endgame nur einmal durch die Kette
Speak rief bei ErrNoByteOutput SpeakDirect auf, das einen eigenen
vollständigen walk machte: fehlgeschlagene Cloud-Stufen wurden zweimal
angefragt (doppelte POSTs auf bezahlten APIs), Fehlschlag-Zeilen
verdoppelten sich im Log, die Worst-Case-Latenz verdoppelte sich, und
Bytes aus einer transienten Erholung im zweiten Durchlauf hätten einen
Fehler statt Wiedergabe produziert.

Speak entscheidet jetzt aus EINEM walk-Ergebnis (Bytes → Player,
nur-Direkt-Stufe → SpeakDirect direkt daran, sonst gebündelter
Stufen-Fehler aus dem geteilten Helper walkResult.noTierErr).
Synthesize/SpeakDirect behalten ihre öffentlichen Verträge; null-Player
verwirft tonlos mit Exit 0 wie zuvor.

Test: TestChainDirektEndgameEinDurchlauf pinnt Cloud-Stufe genau 1×
angefragt, jede Fehlschlag-Zeile genau 1×, Direktansage kommt zustande.
2026-10-18 16:41:23 +02:00
m3ta-chiron 91cd0ec8da feat(provider): Cloud-Provider und Vier-Stufen-Fallback-Kette
- elevenlabs: POST /v1/text-to-speech/{voice}, Header xi-api-key, Body mit
  model_id eleven_multilingual_v2 und voice_settings 0.5/0.75, MP3-Bytes.
- openai: POST /v1/audio/speech, Bearer-Key, Body {model, voice, input,
  response_format:mp3}; Modell konfigurierbar (Default tts-1).
- edge: Microsofts Read-Aloud-WSS-Protokoll nach edge-tts-Referenz,
  inklusive aktuellem DRM Sec-MS-GEC v2 (CS64 + verschleierte SHA-256-
  Variante, wörtlich portiert und gegen Referenzvektoren getestet) und
  MUID-Cookie; bei 403 Uhrenkorrektur aus dem Date-Header + ein Retry.
  Klare Protokoll-geaendert-Fehler statt stiller Fehlfunktion.
- chain: geordnete Kette (elevenlabs -> openai -> edge -> osbuiltin), Pin
  per --provider/config, Available ohne Netz-Calls, Fallback mit
  Protokoll je Stufe (nie still). Chain implementiert Provider UND
  DirectSpeaker: Speak orchestriert Bytes -> Player bzw. Direktansage,
  verwirft am null-Player tonlos — CLI und Daemon (Task 04) nutzen
  dieselbe Kette unverändert.
- voices: neutrale Repo-Defaults je Provider+Sprache (Rachel/alloy/
  Katja/Aria); Rangfolge --voice > config-Mapping > Default. KXxZ… bleibt
  bewusst Privat-Default der eigenen config.toml (Spec: nicht
  Repo-Default).

Tests: Cloud-Provider gegen httptest-Fakes (200/500/401, Request-Vertrag
wörtlich), Edge über Interface + Fehlerpfad-Mocks + Loopback-WSS-Fake
(kein echtes Netz) + als testing.Short überspringbare Integration-
Markierung (TALK_TEST_REAL_EDGE=1, am Dev-Host einmalig ausgeführt:
17136 Bytes echtes Audio). Kette: erster 500 -> zweiter getroffen -> Bytes;
Pin, alle-Stufen-tot, Direktansage mit/ohne null-Player.
2026-10-18 16:34:43 +02:00
m3ta-chiron 5f450ea015 feat(provider): Provider-Vertrag und osbuiltin für OS-eingebautes TTS
Interface Name/Available/Synthesize (Contract für die Kette aus Task 03)
plus dokumentierte optionale Erweiterung DirectSpeaker für Plattformen,
deren OS-TTS keine Audio-Bytes liefert: spd-say (speech-dispatcher) kann
nach --help-Verifikation nur selbst abspielen — dort spricht
SpeakDirect blockierend (spd-say -w -l <lang>). Synthesize liefert
RIFF/WAVE: Linux espeak/espeak-ng (--stdout), macOS say (temporäre
WAV-Datei, LEI16@22050), Windows SAPI (PowerShell, -EncodedCommand).
Tests mit Fake-Prozessen über PATH-Manipulation; echte spd-say-Ausgabe
nur hinter TALK_TEST_REAL_SPD=1.
2026-10-18 15:39:01 +02:00
m3ta-chiron 24dfe4d46c chore: bootstrap go module, license, readme and package skeleton 2026-10-18 15:14:18 +02:00