From 838445ba071e7e198290749227451108d8d0e51c Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Thu, 28 May 2026 01:59:36 +0200 Subject: [PATCH] =?UTF-8?q?Show=20all=20STT/TTS=20backends=20with=20?= =?UTF-8?q?=E2=9C=93/=E2=9C=97=20status=20in=20conversation=20dropdowns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the filter-to-available-only approach with full lists that include unavailable backends (disabled, marked ✗) so users can see what's broken. Also extends STT retry fallback to cover HTTP 500 from wrong model names (fixes faster-whisper CTranslate2 CUDA build issue). Co-Authored-By: Claude Sonnet 4.6 --- server.py | 2 +- static/app.js | 43 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/server.py b/server.py index 2c575e1..2445641 100644 --- a/server.py +++ b/server.py @@ -1974,7 +1974,7 @@ def _transcribe_audio(src: Path, settings: dict, backend: str = "configured") -> headers=hdrs, timeout=_STT_REQUEST_TIMEOUT, ) - if resp.status_code in {400, 404, 422} and model != "whisper-1": + if resp.status_code in {400, 404, 422, 500} and model != "whisper-1": with src.open("rb") as f: resp = requests.post( f"{stt_url}/v1/audio/transcriptions", diff --git a/static/app.js b/static/app.js index aa27df6..a51a417 100644 --- a/static/app.js +++ b/static/app.js @@ -8227,12 +8227,27 @@ $('s-import-voices-file')?.addEventListener('change', async function () { // ── Populate STT backends ──────────────────────────────────────────────── async function loadConvSttBackends() { if (!sttSel) return; + const prev = sttSel.value; try { const d = await fetch('/api/stt-backends').then(r => r.json()); - const avail = (d.backends || []).filter(b => b.available); - sttSel.innerHTML = avail.length - ? avail.map(b => ``).join('') - : ''; + const all = d.backends || []; + if (!all.length) { + sttSel.innerHTML = ''; + return; + } + sttSel.innerHTML = all.map(b => { + const icon = b.available ? '✓' : '✗'; + const label = `${icon} ${escHtml(b.label)}`; + const disabled = !b.available; + return ``; + }).join(''); + // Restore prev selection or pick first available + const opt = sttSel.querySelector(`option[value="${CSS.escape(prev)}"]`); + if (opt && !opt.disabled) { sttSel.value = prev; } + else { + const first = sttSel.querySelector('option:not([disabled])'); + if (first) sttSel.value = first.value; + } } catch(_) { sttSel.innerHTML = ''; } @@ -8241,10 +8256,22 @@ $('s-import-voices-file')?.addEventListener('change', async function () { // ── Populate TTS backends (reuse global _ttsBackends) ─────────────────── function populateConvTtsBackends() { if (!ttsBkSel) return; - const avail = availableTtsBackends(); - ttsBkSel.innerHTML = avail.length - ? avail.map(b => ``).join('') - : ''; + const prev = ttsBkSel.value; + const all = window._ttsBackends || []; + if (!all.length) { + ttsBkSel.innerHTML = ''; + return; + } + ttsBkSel.innerHTML = all.map(b => { + const icon = b.available ? '✓' : '✗'; + return ``; + }).join(''); + const opt = ttsBkSel.querySelector(`option[value="${CSS.escape(prev)}"]`); + if (opt && !opt.disabled) { ttsBkSel.value = prev; } + else { + const first = ttsBkSel.querySelector('option:not([disabled])'); + if (first) ttsBkSel.value = first.value; + } } // ── Fetch LLM models ─────────────────────────────────────────────────────