Skip to content

v2.2.0 — OpenAI-compat polish sweep (9 fixes, 1 CRITICAL)

Choose a tag to compare

@fakehec fakehec released this 18 Apr 18:49
· 10 commits to main since this release

⚠️ CRITICAL: if you are running v2.1.0 and depend on adhoc voice
cloning (custom_voice_file / speaker_wav), upgrade. v2.1.0 on
FastAPI 0.136+ silently ignored uploaded reference audio and returned
default-voice (alloy) output with X-Route: HOT / X-Cache: MISS
headers. v2.2.0 is the first release where cloning actually works
against FastAPI 0.136+ / Starlette 1.0+.

Same root cause as the just-fixed
uttera-tts-vllm v1.2.0
bug: fastapi.datastructures.UploadFile and
starlette.datastructures.UploadFile are now DISTINCT classes, so a
plain isinstance(x, UploadFile) against a Starlette instance
silently returns False.

Fixed

  1. [CRITICAL] Adhoc voice cloning was silently disabled — see
    above.
  2. Unknown voice silently fell back to the default — now
    HTTP 400 with the list of available voices.
  3. response_format outside {mp3, wav, pcm, opus, flac} reached
    ffmpeg and produced HTTP 500. Now validated → HTTP 422.
  4. speed outside [0.25, 4.0] (OpenAI spec) not validated.
    speed=99 → HTTP 500; speed=-1 → HTTP 200 with garbage. Now 422.
  5. temperature outside [0.0, 2.0] not validated. Now 422.
  6. cfg_value outside [0.5, 5.0] (VoxCPM range) not validated.
    Now 422.
  7. JSON body without input raised pydantic.ValidationError
    that escaped as HTTP 500. Now caught → HTTP 422.
  8. Bogus / non-audio custom_voice_file surfaced as HTTP 500.
    Now HTTP 400 with a trimmed decode message.
  9. HEAD /health returned HTTP 405. Now accepted.

Added

  • Opt-in CORSMiddleware via CORS_ALLOW_ORIGINS env var
    (comma-separated list or "*"). Disabled by default.
  • X-Cache: ADHOC response header on adhoc cloning, matching
    uttera-tts-vllm v1.2.0. Adhoc cloning also always bypasses
    the MD5 audio cache (both read and write) — previously the
    cache key used the temp-file path md5 and wrote single-use junk
    entries on every adhoc request (cache pollution).

Changed

  • SERVER_VERSION bumped to 2.2.0. The in-file # Version:
    header comment had been stuck at 2.0.0 since the v2.0.0 release
    (runtime SERVER_VERSION was already tracking). Resynced.
  • /v1/models owned_by rebranded from "stark-fleet" to
    "uttera".

Breaking?

Clients that relied on v2.1.0's silent behaviours will see explicit
errors instead:

  • Unknown voice names now return HTTP 400 (were: alloy audio + 200).
  • Adhoc uploads now actually clone the voice (were: alloy audio).

Every previously-valid request continues to return the same shape.

Verified

  • All 13 validation cases return expected 4xx codes.
  • Adhoc cloning via both custom_voice_file and speaker_wav alias
    emits X-Cache: ADHOC, writes no cache entry, produces audio in
    the cloned voice, and leaves no copy of the uploaded WAV on disk
    (MD5-scan verified).
  • 32-concurrent Coqui burst: 32/32 OK, 0 tracebacks.