feat(1a): Flex-Sprachmodus vollständig entfernen

Sprache ist immer fest. Entfernt: language_mode aus Route/Schema/Config/
Runtime-Config, die Flex-Verzweigung in Orchestrator (effective_language =
language) und ws.py (immer normales transcribe), die "🔄 Flex"-Option im
Frontend samt zugehöriger app.js-Logik (langOverrides, loadMe, Turn-Sprache).

Die generische STT-Methode transcribe_detect bleibt als wiederverwendbare
Infrastruktur erhalten (nicht mehr aufgerufen). Test: Route trägt kein
language_mode mehr. 215 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-25 02:51:17 +02:00
commit be5206c7ed
10 changed files with 24 additions and 64 deletions

View file

@ -13,13 +13,9 @@ const cartesiaHint = $("#cartesia-lang-hint");
let cartesiaUnsupportedLangs = []; // von /api/config: Sprachen, die Cartesia nicht spricht
const CARTESIA_LANG_LABELS = { ar: "Arabisch", it: "Italienisch", ru: "Russisch", pl: "Polnisch", nl: "Niederländisch", sv: "Schwedisch", tr: "Türkisch" };
// "Flex" ist im Sprachmenü nur ein weiterer Wert: keine feste Sprache, sondern
// automatische Erkennung. Eine konkrete Sprache = Fix-Modus (Eingabe wird übersetzt).
// Beide internen Felder (language, language_mode) werden aus dieser einen Auswahl abgeleitet.
// Die gewählte Sprache ist immer fest (Flex-Modus wurde entfernt).
function langOverrides() {
const sel = langSel && langSel.value;
if (!sel || sel === "flex") return { language_mode: "flex" };
return { language: sel, language_mode: "fix" };
return { language: (langSel && langSel.value) || "de" };
}
// Nutzer-Präferenzen als Request-Overrides für jeden Turn.
@ -348,10 +344,7 @@ function loadMe() {
// Gespeicherte Nutzer-Präferenzen in die Dropdowns laden.
const prefs = me.prefs || {};
if (langSel) {
// Flex-Modus -> "flex", sonst die feste Sprache (Fallback: Flex).
langSel.value = prefs.language_mode === "flex"
? "flex"
: (prefs.language || "de");
langSel.value = prefs.language || "de";
}
applyPlaybackChoice(prefs.tts_provider);
applyGenderChoice(prefs.voice_gender || 'f');
@ -544,10 +537,9 @@ function runTurn(path, onopen) {
const pcm = [];
let answerEl = null;
let sampleRate = 24000;
// Sprache dieses Turns (für den Replay je Bubble): Flex folgt erkannter Sprache.
let routeLang = null, routeMode = null, detectedLang = null;
const turnLang = () =>
(routeMode === "flex" ? (detectedLang || routeLang) : routeLang) || null;
// Sprache dieses Turns (für den Replay je Bubble) = feste Routensprache.
let routeLang = null;
const turnLang = () => routeLang || null;
ws.onopen = () => onopen(ws);
ws.onerror = () => { statusEl.textContent = "Verbindungsfehler"; resolve(); };
@ -560,10 +552,8 @@ function runTurn(path, onopen) {
switch (msg.type) {
case "ack":
routeLang = (msg.route && msg.route.language) || null;
routeMode = (msg.route && msg.route.language_mode) || null;
break;
case "transcript":
detectedLang = msg.detected_language || null;
if (msg.text) addMessage("user", msg.text, { lang: turnLang() });
break;
case "token":
@ -620,9 +610,8 @@ async function sendText(text) {
busy = true;
setMicBusy();
await ensureSession();
// Bei fester Sprache wird der eigene Text in dieser Sprache vorgelesen; bei Flex offen.
const lo = langOverrides();
addMessage("user", text, { lang: lo.language_mode === "fix" ? lo.language : null });
addMessage("user", text, { lang: lo.language || null });
statusEl.textContent = "denkt …";
const audioStream = !isDeviceMode(); // Geräte-Modus: kein Server-Audio anfordern
await runTurn("/ws/chat", (ws) => {

View file

@ -219,9 +219,8 @@
<header class="shrink-0 h-14 flex items-center gap-2 px-3 border-b border-slate-200 dark:border-slate-700 bg-white/80 dark:bg-slate-800/80 backdrop-blur">
<img src="/favicon.svg?v=1" alt="" class="w-7 h-7 shrink-0" />
<h1 class="flex-1 truncate font-semibold text-base">Voice&nbsp;Assistant</h1>
<select id="lang-sel" title="Sprache — feste Sprache oder 🔄 Flex (folgt der gesprochenen Sprache)"
<select id="lang-sel" title="Sprache"
class="text-sm rounded-lg border border-slate-300 dark:border-slate-600 bg-transparent px-2 py-1.5">
<option value="flex">🔄 Flex</option>
<option value="de">🇩🇪 DE</option>
<option value="en">🇬🇧 EN</option>
<option value="fr">🇫🇷 FR</option>