Skip to content

v1.2.0 — OpenAI-compat polish sweep (8 fixes, 1 CRITICAL)

Choose a tag to compare

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

⚠️ CRITICAL: if you are running v1.1.0 and depend on adhoc voice
cloning, upgrade. v1.1.0 silently ignored uploaded custom_voice_file
/ speaker_wav bodies and returned default-voice audio. v1.2.0 is
the first release where adhoc cloning actually works end-to-end.

Fixed

  1. [CRITICAL] Adhoc voice cloning was silently disabled. The
    isinstance(spec, UploadFile) check used
    fastapi.datastructures.UploadFile, but Starlette's form parser
    returns starlette.datastructures.UploadFile — distinct classes
    in FastAPI 0.136+ / Starlette 1.0+. The check always returned
    False, speaker_wav never latched, the handler silently fell
    through to the default voice, and the response was cached as a
    regular request (X-Route: HOT, X-Cache: MISS | HIT instead of
    the documented ADHOC / ADHOC). Fixed by matching either class
    plus a duck-type fallback.
  2. Bogus custom_voice_file bodies (non-audio, empty) were
    silently accepted — same root cause. Now rejected with HTTP 400
    and a trimmed decode error.
  3. JSON body without input raised pydantic.ValidationError
    that escaped as HTTP 500 with no body. Now caught → HTTP 422.
  4. speed range validation. Values outside [0.25, 4.0]
    (OpenAI spec) were silently accepted. Now HTTP 422.
  5. speed is now actually applied. The VoxCPM2 engine doesn't
    support variable-rate synthesis natively; speed != 1.0 was
    silently ignored. _encode_audio() now routes every output
    format through an ffmpeg atempo filter chain (chained for
    values < 0.5 or > 2.0).
  6. cfg_value range validation in [0.5, 5.0] (VoxCPM2 safe
    range). Previously any float was accepted, allowing NaN / garbage
    output from the diffusion solver. Now HTTP 422 outside the range.
  7. HEAD /health now accepted (@app.api_route(methods=["GET", "HEAD"])).
    Load-balancer uptime probes no longer get 405s.
  8. Opt-in CORSMiddleware gated on CORS_ALLOW_ORIGINS env var
    (comma-separated list or "*"). Disabled by default — API-first
    deployments don't need it.

Verified

  • 128-concurrent regression burst: 128/128 OK, ~12 rps.
  • Adhoc voice cloning via both custom_voice_file and speaker_wav
    alias emit X-Route: ADHOC and generate audio in the cloned voice.
  • speed=2.0 → ~half-duration audio; speed=0.5 → ~double-duration
    (verified with ffprobe).
  • CORS preflight + actual POST emit the expected headers when
    CORS_ALLOW_ORIGINS is set.
  • Zero HTTP 500s in the sweep log.

Full diff

See CHANGELOG.md.