Resolve #3620140 "Add Qwen3-TTS-12Hz-1.7B-CustomVoice support"

Qwen3-TTS-12Hz-1.7B-CustomVoice is documented as a Text-to-Speech model ("Text to audio"), but text_to_speech was not an implemented operation type in this provider — it was absent from getSupportedOperationTypes() and textToSpeech() threw "not implemented". This adds the operation type along with the model.

POST /v1/audio/speech was confirmed live (401 against a calibrating 404 on a nonsense path). OpenAiBasedProviderClientBase already implements TextToSpeechInterface, so no interface declaration and no composer.json constraint bump were needed.

Changes

  • text_to_speech added to getSupportedOperationTypes().
  • textToSpeech() implemented, replacing the throw.
  • getModels() switch: filter /^(qwen3-tts)/i, replacing the commented-out OpenAI /^(tts)/i.
  • Registered as the text_to_speech default model in getSetupData().
  • definitions/api_defaults.yml: the block still carried OpenAI's voices (alloy, ash, …) and the unsupported aac format. Replaced with mittwald's nine voices, aac dropped, language and speed (0.25–4.0) added.
  • README: section flipped from ⏸️ to , plus voices, formats, a usage example and a configuration subsection.
  • .cspell-project-words.txt: aiden, sohee.

Two API quirks handled explicitly

  1. The response carries an audio/mpeg header regardless of the requested format, so speechResponseType() derives the MIME type and extension from the request. The inherited base implementation hardcodes mp3, which would mislabel every non-mp3 response.
  2. The configuration form submits every field it renders, including untouched ones, so an unset language arrives as ''. Since an invalid voice/language/instructions returns a generic Got bad request. that does not name the parameter, empty optionals are stripped before the request.

Verification

  • verify_class.php: class declares cleanly, TextToSpeechInterface satisfied.
  • verify_filters.php: the model matches text_to_speech and nothing else; no other model's row changed (no prefix over-match).
  • GrumPHP / phpcs pass.
  • Not run: the end-to-end AI API Explorer walkthrough, which needs a running site and a live API key.

Out of scope

Pre-existing drift noticed but deliberately not fixed here: Qwen3.5-0.8B is offered for image vision despite being text-only, and moderation is advertised while its filter matches only OpenAI IDs.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading