# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

---

## [Unreleased]

### Fixed

- **Fast playback on long messages** — chunked inference in auto/design mode was applying the user's `speed` parameter twice: once during the initial full-text duration estimation, and again when estimating duration for subsequent chunks that used the first generated chunk as a reference. Subsequent chunks now correctly use `speed = 1.0` when the reference audio comes from a generated chunk rather than user-provided reference audio. (see `pipeline.rs` `run_chunk_batch` / `run_chunk_batch_device`)
- **Excessive audio chunking in API examples** — server API documentation examples showed `"audio_chunk_duration": 1.0` and `"audio_chunk_threshold": 0.5`, which would cause a 30-second utterance to be split into 30+ tiny chunks with audible cross-fade gaps. Updated examples to reflect actual sensible defaults of `15.0` and `30.0` seconds.
- **Inconsistent reference audio trimming** — when `preprocess_prompt` was enabled, reference audio was only trimmed to 15s if `ref_text` was absent; long audio with a provided transcript was left untrimmed, risking model position embedding overflow. Now reference audio is always trimmed during preprocessing regardless of `ref_text` presence. (see `audio_input.rs`)
- **CUDA crash on long text without explicit duration** — auto-duration estimation for long non-Latin text (e.g., 100+ words of Urdu) produced a target length that exceeded the Qwen3 backbone's `max_position_embeddings`, causing `CUDA_ERROR_INVALID_VALUE` in the RoPE attention kernel. Fixed by expanding `chunk_text_punctuation` to split on Arabic/Devanagari/CJK punctuation (`،` `؛` `؟` `۔` etc.) and adding force-break for unpunctuated runs. Also adds a hard clamp in `prepare_prompt()` so `total_length` can never exceed `max_position_embeddings` minus a safety margin, preventing crashes even if chunking somehow emits an oversized chunk. (see `frontend/mod.rs` `clamp_target_length()`, `frontend/text.rs` `chunk_text_punctuation`)

### Added

- **Vapi `/v1/synthesize` voice profile + query param support** — the Vapi-compatible TTS webhook now accepts voice profiles (`voice`), voice design (`instruct`), language, speed, duration, and all GenerationConfig overrides in either the JSON body or URL query parameters. Also supports auth via `x_vapi_secret` and `api_key` query parameters for platforms that cannot set custom HTTP headers.

### Changed

- Reference audio preprocessing now consistently caps audio to 15 seconds whenever `preprocess_prompt` is true.
- `bolo-voice-service.toml` is now ignored by Git to prevent accidental secret leakage. A template file (`bolo-voice-service.toml.example`) is provided instead.
- **Refactored parameter building into shared `GenerationRequestBuilder`** — created `crates/bolo-tts-server/src/params.rs` with `GenerationRequestBuilder`, `ConfigOverrides`, and shared parsing helpers. The standard `POST /v1/audio/speech` and the Vapi `POST /v1/synthesize` endpoints now both use the same builder, eliminating ~200 lines of duplicated profile resolution, password validation, and generation-config application logic. New endpoints can reuse `GenerationRequestBuilder::new(...)` with minimal duplication.

---

## Historical Notes

This changelog was started on 2026-05-21. Earlier changes are not retroactively documented here.
