Multi-speaker input on /v1/audio/speech and /dev/captioned_speech (#294). Opt in per request with allow_voice_tags: true; disable server-wide with ENABLE_VOICE_TAGS=false.
Inline [voice:name] tags switch speaker mid-text.
voice_aliases mapping for named weighted voice mixes, with optional per-alias rate.
/dev/captioned_speech timestamps carry the resolved voice per word; the field is absent unless allow_voice_tags is on, so existing responses are unchanged.
POST /dev/dialogue for ordered multi-speaker turns.
SSML input (experimental). Disable server-wide with ENABLE_SSML=false.
ssml: true on /v1/audio/speech and /dev/captioned_speech translates and speaks in one call. Requires allow_voice_tags: true, since the translation emits [voice:] and [rate:] spans.
POST /dev/ssml returns the translated tokens as text instead, for inspecting them before synthesis.
return_timing on /v1/audio/speech: per-chunk {text, start, end} JSON sidecar next to the download (powers the web reader).
MAX_PAUSE_DURATION_S (default 60) caps a single [pause:Ns] tag or SSML <break>.
Web UI:
Voice alias/tag cast builder with import/export, pinning, and per-alias rate, synced with the editor (re: parallel work by @radzrader, #272).
Read-along mode: sentence highlighting synced to playback, bidirectional click to seek.
Find/replace across pages, direct page-number entry, download menu (audio / timings / both).
Wiki pages moved into docs/, versioned alongside the code.
Changed
Docker images compile to bytecode at build, ~40% faster startup.
Containers launch uvicorn directly rather than through uv run, which resolves startup permission failures on Unraid and similar hosts.
[rate:] tags scale the speaking voice's alias rate instead of replacing it, so a voice calibrated to 0.8 stays proportionally slower under [rate:1.1]. Matches how SSML engines treat rate.
Speed bounds (0.25 to 4.0) shared across speed fields and SSML.
Unrecognized .env keys warn at startup instead of refusing to boot.
README config table now covers every setting.
Fixed
Long generations swap from the live stream to the finished file as soon as it lands, so the scrubber shows true duration and seeking works mid-run.
Volume control state reconnected to the player.
Removed
Unused ffmpeg from all images (~600MB); audio encoding already runs through PyAV's bundled copy.
Dead pydub dependency.
Unreachable list form of voice from the speech parser and unused VoiceCombineRequest schema.
Legacy Gradio UI (ui/) code cruft; superseded by the web player since ~v0.2.0
fastapi>=0.128.8, starlette>=1.3.1 to close CVE-2025-62727 (quadratic Range header parsing in FileResponse, reachable through the audio download path) (#500).
Changed
CORS allow_credentials now defaults off. Starlette 1.x echoes the caller's origin with allow-credentials: true where 0.47 returned *; nothing here uses cookies or auth, so this keeps the prior behavior.
Docker build cache moved from GHA to the GHCR registry so forks and local builds can pull it, plus uv cache mounts and reordered test-client layers (#501).
response_format docs (correctly) now list aac as supported.
Fixed
FLAC and WAV no longer lose the tail end of the audio; better muxer header patching at finalize (#497, covers #448 and #463). Diagnosis by @Technologicat.
/v1/download/{filename} takes an optional ?name= save-as name (sanitized, stored extension kept) and sets it in Content-Disposition. Omitting it keeps the previous name.
Web UI keyboard navigation and ARIA labeling across header, player controls, and editor.
Changed
Content-Disposition is now built by FileResponse rather than by hand, so the filename comes back quoted (filename="x.mp3") instead of bare. The name itself is unchanged when ?name= is omitted.
Web UI restyle: better use of space, responsive down to slim widths, playbar pinned to the bottom on narrow viewports.
Waveform slowed and softened, made framerate-independent, respects prefers-reduced-motion.
Downloads save as {voice}_{timestamp}.{format}, not the temp name (#338). Covers right-click "Save audio as" too, since Content-Disposition outranks the link's download attribute.
Aborted streams no longer surface as playback failures; a user-initiated MEDIA_ERR_ABORTED is told apart from a real error.
Stream-to-file swap settles pending buffer operations instead of leaving the feeder awaiting forever.
Builds now explicitly require BuildKit (default since Docker 23, ~Jan 2023); utilizing COPY --exclude
Model bake reworked to ensure weights land exactly once (whether prexisting or downloaded at build)
ROCm image now bakes the model at build like CPU/GPU (instead of a first-run fetch)
GPU runtime now only uses torch shipped cuDNN/etc via pip wheels (#482). (see table below for size changes)
Transcription benchmark reports split by device; RTF and first-token baselines refreshed.
Compressed image sizes + new bases:
Image
v0.6.0
v0.7.0
Runtime base
cpu
1.66 GB
1.56 GB
python:3.10-slim -> python:3.12-slim
gpu
6.81 GB
4.68 GB
cuda:12.6.3-cudnn-runtime -> cuda:12.6.3-base
gpu (cu128)
8.11 GB
5.23 GB
cuda:12.8.1-cudnn-runtime -> cuda:12.8.1-base
rocm
13.08 GB
13.36 GB
unchanged; model now baked in
Fixed
Model validation checksums against downloaded release artifact to ensure consistency, downloads first to a temp dir to avoid clobbering pre-existing models in the case of network issues/corrupted downloads.
Model validation also rejects any custom files under 100MB to avoids false pass results (e.g. a 9-byte "Not found"), allowing a re-download instead of passing (#301).
.dockerignore Fixed pycache ignore pattern to **/ to ensure nested .pyc/etc stay out of build contexts.
Removed dead pydub imports from the audio services.
_find_file rejects lookups that escape its search roots (../ sequences, absolute paths) to avoid unintentional exposure of files outside the voices/models/web dirs. Symlinks placed inside those dirs resolve as before.
Text normalizer: anchored decimal regex to prevent quadratic backtracking on digit floods, reordered range substitution so NUMBER_PATTERN no longer swallows hyphens meant as range separators, added version-number handling (2.0.1 renders as "two point zero point one" instead of being split).
Configuration
📅Schedule: (UTC)
Branch creation
At any time (no schedule defined)
Automerge
At any time (no schedule defined)
🚦Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕Ignore: Close this PR and you won't be reminded about this update again.
If you want to rebase/retry this PR, check this box
This PR contains the following updates:
| Package | Update | Change |
|---|---|---|
| [ghcr.io/remsky/kokoro-fastapi-cpu](https://github.com/remsky/Kokoro-FastAPI) | minor | `v0.6.0` → `v0.8.0` |
---
### Release Notes
<details>
<summary>remsky/Kokoro-FastAPI (ghcr.io/remsky/kokoro-fastapi-cpu)</summary>
### [`v0.8.0`](https://github.com/remsky/Kokoro-FastAPI/blob/HEAD/CHANGELOG.md#v080---2026-08-14)
[Compare Source](https://github.com/remsky/Kokoro-FastAPI/compare/v0.7.2...v0.8.0)
##### Added
- Multi-speaker input on `/v1/audio/speech` and `/dev/captioned_speech` ([#​294](https://github.com/remsky/Kokoro-FastAPI/issues/294)). Opt in per request with `allow_voice_tags: true`; disable server-wide with `ENABLE_VOICE_TAGS=false`.
- Inline `[voice:name]` tags switch speaker mid-text.
- `voice_aliases` mapping for named weighted voice mixes, with optional per-alias `rate`.
- `/dev/captioned_speech` timestamps carry the resolved `voice` per word; the field is absent unless `allow_voice_tags` is on, so existing responses are unchanged.
- `POST /dev/dialogue` for ordered multi-speaker turns.
- SSML input (experimental). Disable server-wide with `ENABLE_SSML=false`.
- `ssml: true` on `/v1/audio/speech` and `/dev/captioned_speech` translates and speaks in one call. Requires `allow_voice_tags: true`, since the translation emits `[voice:]` and `[rate:]` spans.
- `POST /dev/ssml` returns the translated tokens as text instead, for inspecting them before synthesis.
- `return_timing` on `/v1/audio/speech`: per-chunk `{text, start, end}` JSON sidecar next to the download (powers the web reader).
- `MAX_PAUSE_DURATION_S` (default 60) caps a single `[pause:Ns]` tag or SSML `<break>`.
- Web UI:
- Voice alias/tag cast builder with import/export, pinning, and per-alias rate, synced with the editor (re: parallel work by [@​radzrader](https://github.com/radzrader), [#​272](https://github.com/remsky/Kokoro-FastAPI/discussions/272)).
- Read-along mode: sentence highlighting synced to playback, bidirectional click to seek.
- Find/replace across pages, direct page-number entry, download menu (audio / timings / both).
- Wiki pages moved into `docs/`, versioned alongside the code.
##### Changed
- Docker images compile to bytecode at build, \~40% faster startup.
- Containers launch uvicorn directly rather than through `uv run`, which resolves startup permission failures on Unraid and similar hosts.
- `[rate:]` tags scale the speaking voice's alias rate instead of replacing it, so a voice calibrated to 0.8 stays proportionally slower under `[rate:1.1]`. Matches how SSML engines treat rate.
- Speed bounds (0.25 to 4.0) shared across speed fields and SSML.
- Unrecognized `.env` keys warn at startup instead of refusing to boot.
- README config table now covers every setting.
##### Fixed
- Long generations swap from the live stream to the finished file as soon as it lands, so the scrubber shows true duration and seeking works mid-run.
- Volume control state reconnected to the player.
##### Removed
- Unused `ffmpeg` from all images (\~600MB); audio encoding already runs through PyAV's bundled copy.
- Dead `pydub` dependency.
- Unreachable list form of `voice` from the speech parser and unused `VoiceCombineRequest` schema.
- Legacy Gradio UI (`ui/`) code cruft; superseded by the web player since \~v0.2.0
- Legacy ONNX config compose vars, endpoints e.g `/debug/session_pools`.
- `OUTPUT_DIR`, `OUTPUT_DIR_SIZE_LIMIT_MB`, `SAMPLE_RATE` settings, never read.
### [`v0.7.2`](https://github.com/remsky/Kokoro-FastAPI/blob/HEAD/CHANGELOG.md#v072-2026-08-06)
[Compare Source](https://github.com/remsky/Kokoro-FastAPI/compare/v0.7.1...v0.7.2)
##### Security
- `fastapi>=0.128.8`, `starlette>=1.3.1` to close CVE-2025-62727 (quadratic `Range` header parsing in `FileResponse`, reachable through the audio download path) ([#​500](https://github.com/remsky/Kokoro-FastAPI/issues/500)).
##### Changed
- CORS `allow_credentials` now defaults off. Starlette 1.x echoes the caller's origin with `allow-credentials: true` where 0.47 returned `*`; nothing here uses cookies or auth, so this keeps the prior behavior.
- Docker build cache moved from GHA to the GHCR registry so forks and local builds can pull it, plus uv cache mounts and reordered test-client layers ([#​501](https://github.com/remsky/Kokoro-FastAPI/issues/501)).
- `response_format` docs (correctly) now list `aac` as supported.
##### Fixed
- FLAC and WAV no longer lose the tail end of the audio; better muxer header patching at finalize ([#​497](https://github.com/remsky/Kokoro-FastAPI/issues/497), covers [#​448](https://github.com/remsky/Kokoro-FastAPI/issues/448) and [#​463](https://github.com/remsky/Kokoro-FastAPI/issues/463)). Diagnosis by [@​Technologicat](https://github.com/Technologicat).
### [`v0.7.1`](https://github.com/remsky/Kokoro-FastAPI/blob/HEAD/CHANGELOG.md#v071---2026-08-02)
[Compare Source](https://github.com/remsky/Kokoro-FastAPI/compare/v0.7.0...v0.7.1)
##### Added
- `/v1/download/{filename}` takes an optional `?name=` save-as name (sanitized, stored extension kept) and sets it in `Content-Disposition`. Omitting it keeps the previous name.
- Web UI keyboard navigation and ARIA labeling across header, player controls, and editor.
##### Changed
- `Content-Disposition` is now built by `FileResponse` rather than by hand, so the filename comes back quoted (`filename="x.mp3"`) instead of bare. The name itself is unchanged when `?name=` is omitted.
- Web UI restyle: better use of space, responsive down to slim widths, playbar pinned to the bottom on narrow viewports.
- Waveform slowed and softened, made framerate-independent, respects `prefers-reduced-motion`.
- README: AMD GPU (ROCm) troubleshooting, clarified docker-compose comments.
##### Fixed
- Downloads save as `{voice}_{timestamp}.{format}`, not the temp name ([#​338](https://github.com/remsky/Kokoro-FastAPI/issues/338)). Covers right-click "Save audio as" too, since `Content-Disposition` outranks the link's `download` attribute.
- Aborted streams no longer surface as playback failures; a user-initiated `MEDIA_ERR_ABORTED` is told apart from a real error.
- Stream-to-file swap settles pending buffer operations instead of leaving the feeder awaiting forever.
### [`v0.7.0`](https://github.com/remsky/Kokoro-FastAPI/blob/HEAD/CHANGELOG.md#v070---2026-07-31)
[Compare Source](https://github.com/remsky/Kokoro-FastAPI/compare/v0.6.0...v0.7.0)
##### Added
- `AGENTS.md` contributor guidelines, plus `SKILL.md` notes for the API, benchmarks, and web areas.
##### Changed / Optimizations
- Docker images build on Python 3.12 (project floor stays 3.10 for local installs). Rust dropped from the CPU builder.
- Runtime dependencies trimmed to remove deprecated imports
- bumped `requests`,`python-dotenv`, capped `transformers<6`
- Builds now explicitly require BuildKit (default since Docker 23, \~Jan 2023); utilizing `COPY --exclude`
- Model bake reworked to ensure weights land exactly once (whether prexisting or downloaded at build)
- ROCm image now bakes the model at build like CPU/GPU (instead of a first-run fetch)
- GPU runtime now only uses torch shipped cuDNN/etc via pip wheels ([#​482](https://github.com/remsky/Kokoro-FastAPI/issues/482)). (see table below for size changes)
- Transcription benchmark reports split by device; RTF and first-token baselines refreshed.
Compressed image sizes + new bases:
<div align="center">
| Image | v0.6.0 | v0.7.0 | Runtime base |
| :---------- | -------: | -------: | :------------------------------------------------ |
| cpu | 1.66 GB | 1.56 GB | `python:3.10-slim` -> `python:3.12-slim` |
| gpu | 6.81 GB | 4.68 GB | `cuda:12.6.3-cudnn-runtime` -> `cuda:12.6.3-base` |
| gpu (cu128) | 8.11 GB | 5.23 GB | `cuda:12.8.1-cudnn-runtime` -> `cuda:12.8.1-base` |
| rocm | 13.08 GB | 13.36 GB | unchanged; model now baked in |
</div>
##### Fixed
- Model validation checksums against downloaded release artifact to ensure consistency, downloads first to a temp dir to avoid clobbering pre-existing models in the case of network issues/corrupted downloads.
- Model validation also rejects any custom files under 100MB to avoids false pass results (e.g. a 9-byte "Not found"), allowing a re-download instead of passing (#​301).
- `.dockerignore` Fixed pycache ignore pattern to `**/` to ensure nested .pyc/etc stay out of build contexts.
- Removed dead `pydub` imports from the audio services.
- `_find_file` rejects lookups that escape its search roots (`../` sequences, absolute paths) to avoid unintentional exposure of files outside the voices/models/web dirs. Symlinks placed inside those dirs resolve as before.
- Text normalizer: anchored decimal regex to prevent quadratic backtracking on digit floods, reordered range substitution so `NUMBER_PATTERN` no longer swallows hyphens meant as range separators, added version-number handling (`2.0.1` renders as "two point zero point one" instead of being split).
</details>
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC41LjMiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zMC40IiwidGFyZ2V0QnJhbmNoIjoiZnJlc2gtc3RhcnQiLCJsYWJlbHMiOltdfQ==-->
Renovate
changed title from Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.0 to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.12026-08-03 02:01:32 +00:00
Renovate
changed title from Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.1 to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.22026-08-07 20:54:47 +00:00
Renovate
changed title from Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.2 to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.8.02026-08-16 20:13:27 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
This PR contains the following updates:
v0.6.0→v0.8.0Release Notes
remsky/Kokoro-FastAPI (ghcr.io/remsky/kokoro-fastapi-cpu)
v0.8.0Compare Source
Added
/v1/audio/speechand/dev/captioned_speech(#294). Opt in per request withallow_voice_tags: true; disable server-wide withENABLE_VOICE_TAGS=false.[voice:name]tags switch speaker mid-text.voice_aliasesmapping for named weighted voice mixes, with optional per-aliasrate./dev/captioned_speechtimestamps carry the resolvedvoiceper word; the field is absent unlessallow_voice_tagsis on, so existing responses are unchanged.POST /dev/dialoguefor ordered multi-speaker turns.ENABLE_SSML=false.ssml: trueon/v1/audio/speechand/dev/captioned_speechtranslates and speaks in one call. Requiresallow_voice_tags: true, since the translation emits[voice:]and[rate:]spans.POST /dev/ssmlreturns the translated tokens as text instead, for inspecting them before synthesis.return_timingon/v1/audio/speech: per-chunk{text, start, end}JSON sidecar next to the download (powers the web reader).MAX_PAUSE_DURATION_S(default 60) caps a single[pause:Ns]tag or SSML<break>.docs/, versioned alongside the code.Changed
uv run, which resolves startup permission failures on Unraid and similar hosts.[rate:]tags scale the speaking voice's alias rate instead of replacing it, so a voice calibrated to 0.8 stays proportionally slower under[rate:1.1]. Matches how SSML engines treat rate..envkeys warn at startup instead of refusing to boot.Fixed
Removed
ffmpegfrom all images (~600MB); audio encoding already runs through PyAV's bundled copy.pydubdependency.voicefrom the speech parser and unusedVoiceCombineRequestschema.ui/) code cruft; superseded by the web player since ~v0.2.0/debug/session_pools.OUTPUT_DIR,OUTPUT_DIR_SIZE_LIMIT_MB,SAMPLE_RATEsettings, never read.v0.7.2Compare Source
Security
fastapi>=0.128.8,starlette>=1.3.1to close CVE-2025-62727 (quadraticRangeheader parsing inFileResponse, reachable through the audio download path) (#500).Changed
allow_credentialsnow defaults off. Starlette 1.x echoes the caller's origin withallow-credentials: truewhere 0.47 returned*; nothing here uses cookies or auth, so this keeps the prior behavior.response_formatdocs (correctly) now listaacas supported.Fixed
v0.7.1Compare Source
Added
/v1/download/{filename}takes an optional?name=save-as name (sanitized, stored extension kept) and sets it inContent-Disposition. Omitting it keeps the previous name.Changed
Content-Dispositionis now built byFileResponserather than by hand, so the filename comes back quoted (filename="x.mp3") instead of bare. The name itself is unchanged when?name=is omitted.prefers-reduced-motion.Fixed
{voice}_{timestamp}.{format}, not the temp name (#338). Covers right-click "Save audio as" too, sinceContent-Dispositionoutranks the link'sdownloadattribute.MEDIA_ERR_ABORTEDis told apart from a real error.v0.7.0Compare Source
Added
AGENTS.mdcontributor guidelines, plusSKILL.mdnotes for the API, benchmarks, and web areas.Changed / Optimizations
requests,python-dotenv, cappedtransformers<6COPY --excludeCompressed image sizes + new bases:
python:3.10-slim->python:3.12-slimcuda:12.6.3-cudnn-runtime->cuda:12.6.3-basecuda:12.8.1-cudnn-runtime->cuda:12.8.1-baseFixed
.dockerignoreFixed pycache ignore pattern to**/to ensure nested .pyc/etc stay out of build contexts.pydubimports from the audio services._find_filerejects lookups that escape its search roots (../sequences, absolute paths) to avoid unintentional exposure of files outside the voices/models/web dirs. Symlinks placed inside those dirs resolve as before.NUMBER_PATTERNno longer swallows hyphens meant as range separators, added version-number handling (2.0.1renders as "two point zero point one" instead of being split).Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate CLI.
6dd9ed67f7to515862602aUpdate ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.0to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.1515862602ato8ce95d8f94Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.1to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.2Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.7.2to Update ghcr.io/remsky/kokoro-fastapi-cpu Docker tag to v0.8.08ce95d8f94to96ef9a9925