fix(stt): iOS-Live-Vorschau wiederhergestellt + klare Server-Fallback-Meldung
- resolveSttMode behandelt iOS-Safari (keine available()-API) wieder als "local" -> on-device SpeechRecognition mit Live-Interim funktioniert auf iPhone wieder. - Server-Fallback zeigt jetzt "Server-Erkennung. Live-Vorschau nur mit lokalem/ Cloud-STT" (startRecording optionaler Status-Text) statt generischem Hinweis. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
dc597bd77b
commit
f74d2fadb2
2 changed files with 13 additions and 9 deletions
|
|
@ -172,6 +172,7 @@ let recognition = null;
|
||||||
// "server" (Whisper-Fallback). Nutzt die Chrome-API available()/install() für die
|
// "server" (Whisper-Fallback). Nutzt die Chrome-API available()/install() für die
|
||||||
// On-Device-Sprachpakete — verhindert "language not supported", wenn das Paket fehlt.
|
// On-Device-Sprachpakete — verhindert "language not supported", wenn das Paket fehlt.
|
||||||
async function resolveSttMode(bcp) {
|
async function resolveSttMode(bcp) {
|
||||||
|
// Chrome (neue API): prüft, ob das On-Device-Sprachpaket vorhanden ist.
|
||||||
if (SR && typeof SR.available === "function") {
|
if (SR && typeof SR.available === "function") {
|
||||||
try {
|
try {
|
||||||
const a = await SR.available({ langs: [bcp], processLocally: true });
|
const a = await SR.available({ langs: [bcp], processLocally: true });
|
||||||
|
|
@ -180,17 +181,22 @@ async function resolveSttMode(bcp) {
|
||||||
// On-Device-Paket anstoßen (für künftige Turns); jetzt Cloud/Server.
|
// On-Device-Paket anstoßen (für künftige Turns); jetzt Cloud/Server.
|
||||||
try { if (typeof SR.install === "function") SR.install({ langs: [bcp], processLocally: true }); } catch (e) {}
|
try { if (typeof SR.install === "function") SR.install({ langs: [bcp], processLocally: true }); } catch (e) {}
|
||||||
}
|
}
|
||||||
|
return meAllowCloudStt ? "cloud" : "server";
|
||||||
} catch (e) { /* API-Fehler -> unten */ }
|
} catch (e) { /* API-Fehler -> unten */ }
|
||||||
}
|
}
|
||||||
|
// Keine available()-API: iOS-Safari erkennt on-device (mit Live-Vorschau) -> lokal.
|
||||||
|
if (isIOS()) return "local";
|
||||||
|
// Sonst (z. B. älteres Chrome): SpeechRecognition liefe über die Cloud.
|
||||||
return meAllowCloudStt ? "cloud" : "server";
|
return meAllowCloudStt ? "cloud" : "server";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SERVER_STT_MSG = "Server-Erkennung. Live-Vorschau nur mit lokalem/Cloud-STT";
|
||||||
|
|
||||||
async function startDeviceStt() {
|
async function startDeviceStt() {
|
||||||
const bcp = LANG_BCP47[langSel.value] || "de-DE";
|
const bcp = LANG_BCP47[langSel.value] || "de-DE";
|
||||||
const mode = await resolveSttMode(bcp);
|
const mode = await resolveSttMode(bcp);
|
||||||
if (mode === "server") { // lokal (für diese Sprache) nicht da & Cloud verboten
|
if (mode === "server") { // lokal (für diese Sprache) nicht da & Cloud verboten
|
||||||
statusEl.textContent = "erkenne über Server …";
|
startRecording(SERVER_STT_MSG);
|
||||||
startRecording();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rec = new SR();
|
const rec = new SR();
|
||||||
|
|
@ -216,8 +222,7 @@ async function startDeviceStt() {
|
||||||
if (err === "no-speech") { setMicIdle(); statusEl.textContent = "nichts gehört — bitte erneut"; return; }
|
if (err === "no-speech") { setMicIdle(); statusEl.textContent = "nichts gehört — bitte erneut"; return; }
|
||||||
// Sprache/Dienst/Netz nicht verfügbar -> sauber auf Server-STT zurückfallen statt Fehler.
|
// Sprache/Dienst/Netz nicht verfügbar -> sauber auf Server-STT zurückfallen statt Fehler.
|
||||||
if (err === "language-not-supported" || err === "service-not-allowed" || err === "network") {
|
if (err === "language-not-supported" || err === "service-not-allowed" || err === "network") {
|
||||||
statusEl.textContent = "erkenne über Server …";
|
startRecording(SERVER_STT_MSG);
|
||||||
startRecording();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMicIdle();
|
setMicIdle();
|
||||||
|
|
@ -232,8 +237,7 @@ async function startDeviceStt() {
|
||||||
};
|
};
|
||||||
try { rec.start(); } catch (e) {
|
try { rec.start(); } catch (e) {
|
||||||
recognition = null;
|
recognition = null;
|
||||||
statusEl.textContent = "erkenne über Server …";
|
startRecording(SERVER_STT_MSG); // Start scheiterte -> Server-Fallback
|
||||||
startRecording(); // Start scheiterte -> Server-Fallback
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function stopDeviceStt() { if (recognition) { try { recognition.stop(); } catch (e) {} } }
|
function stopDeviceStt() { if (recognition) { try { recognition.stop(); } catch (e) {} } }
|
||||||
|
|
@ -592,7 +596,7 @@ formEl.addEventListener("submit", (e) => {
|
||||||
let mediaRecorder = null;
|
let mediaRecorder = null;
|
||||||
let recChunks = [];
|
let recChunks = [];
|
||||||
|
|
||||||
async function startRecording() {
|
async function startRecording(statusText) {
|
||||||
if (busy) return;
|
if (busy) return;
|
||||||
const md = navigator.mediaDevices;
|
const md = navigator.mediaDevices;
|
||||||
if (!md || !md.getUserMedia) {
|
if (!md || !md.getUserMedia) {
|
||||||
|
|
@ -630,7 +634,7 @@ async function startRecording() {
|
||||||
};
|
};
|
||||||
mediaRecorder.start();
|
mediaRecorder.start();
|
||||||
setMicRecording();
|
setMicRecording();
|
||||||
statusEl.textContent = "Aufnahme … (zum Stoppen erneut tippen)";
|
statusEl.textContent = statusText || "Aufnahme … (zum Stoppen erneut tippen)";
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopRecording() {
|
function stopRecording() {
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,6 @@
|
||||||
<div id="status" class="w-full max-w-3xl mx-auto mt-1 min-h-[1rem] text-xs text-slate-500 dark:text-slate-400"></div>
|
<div id="status" class="w-full max-w-3xl mx-auto mt-1 min-h-[1rem] text-xs text-slate-500 dark:text-slate-400"></div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/app.js?v=33"></script>
|
<script src="/app.js?v=34"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue