docs(lobe-chat): TTS works with zero client-side settings now

infra-ops aliased tts-1, tts-1-hd and gpt-4o-mini-tts onto ext-tts's upstream
and extended the lobe-chat-esh key allow-list 20 -> 23 models, so the manual
"set the TTS model to ext-tts, per browser" step this file described a few
hours ago is obsolete. Lobe's stock three-field payload now returns 200
audio/mpeg — verified from the host with this stack's own .env.

Adds the coupling that the fix introduces: the three new names are independent
LiteLLM DB rows carrying their own copy of the upstream URL, so a future
repoint of ext-tts must move all four or stock clients land on a dead engine
without any error on the gateway side.

Comment/doc only — no functional change, no redeploy.
This commit is contained in:
vh
2026-08-17 21:49:04 -07:00
parent 637ed3bd89
commit d3e1cc4a41
2 changed files with 27 additions and 16 deletions
+18 -10
View File
@@ -50,12 +50,16 @@ model are a **one-time UI setup per browser**, not a maintenance surface. That i
> 1. **"An unknown `model` routes to the gateway default" — false on this path.**
> True direct-to-`:8198`, which accepts-and-ignores `model`. But requests go
> through **LiteLLM**, which resolves the model name *first*. Lobe's default is
> `tts-1`, and `POST $OPENAI_PROXY_URL/audio/speech {"model":"tts-1",...}` returns
> **403 `key not allowed to access model`** (the scoped key's allow-list holds
> `ext-tts` alone; on an unscoped key it is a 400 `Invalid model name`). The same
> call with `"model":"ext-tts"` returns 200 + audio. **So TTS was dead on arrival
> from deploy until the model field was set** — the endpoint being wired is
> necessary, not sufficient.
> `tts-1`, and `POST $OPENAI_PROXY_URL/audio/speech {"model":"tts-1",...}` returned
> **403 `key not allowed to access model`** (the scoped key's allow-list held
> `ext-tts` alone; on an unscoped key it is a 400 `Invalid model name`). **So TTS
> was dead on arrival from deploy until 2026-08-17** — the endpoint being wired is
> necessary, not sufficient. **Fixed the same day**: infra-ops aliased `tts-1`,
> `tts-1-hd` and `gpt-4o-mini-tts` to ext-tts's upstream and extended the
> `lobe-chat-esh` key allow-list 20 → 23 models, so the stock payload now works
> with **zero client-side settings** (verified from this host with this `.env`:
> 200, `audio/mpeg`, real MP3). Setting the UI model field to `ext-tts` remains
> valid and harmless.
> 2. **"`response_format: mp3` … set it in the UI" — not possible.** Lobe's OpenAI
> TTS client sends exactly three fields (server bundle `chunks/29685.js`):
> `{ input, model: options?.model || 'tts-1', voice }`. `response_format` is never
@@ -65,10 +69,14 @@ model are a **one-time UI setup per browser**, not a maintenance surface. That i
> regardless of the bytes. Chrome sniffs and plays it. Fixing the size is
> tts-dev's side of the fence, not a setting here.
>
> **To make TTS work in a browser today:** Settings → TTS → *OpenAI TTS model* →
> `ext-tts`. Per browser, because the settings store is client-side. Removing that
> manual step means aliasing `tts-1` → `ext-tts` in LiteLLM **and** adding it to the
> `lobe-chat-esh` key's allow-list — both master-key operations (infra-ops).
> **Nothing to do in the browser any more.** The alias + allow-list pair above
> removed the manual step entirely; a fresh browser, a phone, or any stock OpenAI
> client works out of the box.
>
> ⚠️ **Coupling worth knowing:** `tts-1`, `tts-1-hd` and `gpt-4o-mini-tts` are
> independent LiteLLM DB rows pointing at ext-tts's upstream, not references to
> `ext-tts`. If that upstream ever repoints, all four move together or stock
> clients quietly land on a dead engine.
Trade recorded for the record: Open WebUI has dedicated `AUDIO_TTS_*` env vars (fully
scriptable) at 1,825 MB; Lobe is endpoint-env + UI-cosmetic at 143 MB. Operator chose
+9 -6
View File
@@ -35,12 +35,15 @@
# ALIASED, not rejected (echo/alloy/onyx/ash->donut, nova->miranda,
# shimmer/coral->emmie, fable/sage->glados), so a UI mis-click is NOT the
# hazard I first recorded. Only `ballad` and `verse` 404 -- both aliased since.
# ⚠️ REQUIRED UI STEP (tts-dev 2026-08-17): Settings -> TTS -> OpenAI TTS model
# -> `ext-tts`. There is no env var for it. Lobe's default is `tts-1`, and while
# :8198 ignores `model`, LITELLM IN FRONT OF IT DOES NOT -- it resolves the name
# first, so `tts-1` returns 403 (`key not allowed to access model`; 400 on an
# unscoped key) and TTS does nothing. Verified from this host with this .env.
# Per browser -- the TTS settings store is client-side.
# MODEL NAME -- no longer a manual step (2026-08-17). Lobe defaults to `tts-1`,
# and while :8198 ignores `model`, LITELLM IN FRONT OF IT DOES NOT -- it resolves
# the name first, so `tts-1` used to 403 (`key not allowed to access model`) and
# TTS did nothing from deploy until it was found. infra-ops then aliased `tts-1`,
# `tts-1-hd` and `gpt-4o-mini-tts` to ext-tts's upstream AND added them to the
# `lobe-chat-esh` key allow-list, so the stock payload works with ZERO settings.
# Verified from this host with this .env: {"input":...,"model":"tts-1",
# "voice":"alloy"} -> 200 audio/mpeg. Setting the UI field to `ext-tts` also
# works and does no harm.
# SIZE: Lobe sends only {input, model, voice} -- no `response_format`, no
# `speed`, and no UI field for either -- so you get the gateway's default (WAV,
# ~23.5 MB for a 245 s turn), relabelled `audio/mpeg` by LiteLLM. Not fixable