feat(P3): Diktat in Fremdsprache → Übersetzung in die Zielsprache

Spricht der Nutzer in einer anderen als der eingestellten Sprache, erkennt
das System die gesprochene Sprache automatisch (transcribe_detect) und
übersetzt die Anfrage per LLM in die Zielsprache — sie wird dann auch in
der Zielsprache angezeigt und verarbeitet. Hilft beim Sprachenlernen und in
der Kommunikation über Sprachgrenzen.

- Orchestrator.translate() (LLM-basiert, nur Übersetzung).
- ws.py Voice-STT: transcribe_detect + Übersetzung bei abweichender Sprache.
- Test-Stubs um transcribe_detect ergänzt; neuer Übersetzungstest. 209 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 03:30:37 +02:00
commit a7f718192f
4 changed files with 70 additions and 2 deletions

View file

@ -73,6 +73,9 @@ def _install_voice_stubs(monkeypatch):
async def transcribe(self, audio_bytes, fmt, language=None):
return f"erkannt({len(audio_bytes)})"
async def transcribe_detect(self, audio_bytes, fmt, language=None):
return f"erkannt({len(audio_bytes)})", None
class StubLLM:
async def complete(self, text, history=None, session_id=None, language=None):
return f"Antwort zu {text}"
@ -155,3 +158,33 @@ def test_ws_voice_empty_buffer_errors(monkeypatch):
ws.send_json({"type": "end", **opts}) # kein Audio gesendet
err = ws.receive_json()
assert err["type"] == "error" and "no audio" in err["detail"]
def test_ws_voice_translates_foreign_language_to_target(monkeypatch):
# Diktat in einer anderen Sprache (detected=fr) bei Zielsprache de ->
# die Anfrage wird übersetzt und in der Zielsprache angezeigt.
class StubSTT:
async def transcribe_detect(self, audio_bytes, fmt, language=None):
return "bonjour, comment ça va", "fr"
class StubLLM:
async def complete(self, text, history=None, session_id=None, language=None):
# Übersetzungs- UND Antwort-Aufruf liefern denselben Stub-Text.
return "GUTEN TAG"
class StubTTS:
async def synthesize(self, text, voice=None, audio_format="pcm", language=None):
return b"A"
monkeypatch.setitem(deps.STT_REGISTRY, "ss", lambda s: StubSTT())
monkeypatch.setitem(deps.LLM_REGISTRY, "ll", lambda s: StubLLM())
monkeypatch.setitem(deps.TTS_REGISTRY, "tt", lambda s: StubTTS())
opts = {"stt_provider": "ss", "llm_provider": "ll", "tts_provider": "tt",
"output_endpoint": "loopback", "language": "de"}
with client.websocket_connect("/ws/voice") as ws:
ws.send_json({"type": "start", "format": "wav", **opts})
ws.send_bytes(b"PCMDATA")
ws.send_json({"type": "end"})
transcript = ws.receive_json()
# Übersetzte (deutsche) Fassung wird angezeigt, nicht das französische Original.
assert transcript["type"] == "transcript" and transcript["text"] == "GUTEN TAG"