Fix MiniMax (TTS) pitch on API calls being the wrong range (#4578) * fix: change MiniMax TTS pitch from float range 0.5-2.0 to integer range -12 to 12 Fixes #4570 * refactor: replace hardcoded defaults with defaultSettings in MiniMaxTtsProvider config * refactor: restructure TTS settings with min/max ranges and add value clamping, adjust volume range * fix: flatten MiniMaxTtsProvider settings to use default values from complex field definitions * Adjust block spacing --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -1,3 +1,8 @@ | ||
| 1 | +.minimax_tts_settings>.tts_block { | |
| 2 | + gap: 5px; | |
| 3 | + margin: 5px 0; | |
| 4 | +} | |
| 5 | + | |
| 1 | 6 | .minimax-custom-item { |
| 2 | 7 | display: flex; |
| 3 | 8 | justify-content: space-between; |
| @@ -19,9 +19,9 @@ class MiniMaxTtsProvider { | ||
| 19 | 19 | apiHost: 'https://api.minimax.io', |
| 20 | 20 | model: 'speech-02-hd', |
| 21 | 21 | voiceMap: {}, |
| 22 | - speed: 1.0, | |
| 22 | + speed: { default: 1.0, min: 0.5, max: 2.0, step: 0.1 }, | |
| 23 | - volume: 1.0, | |
| 23 | + volume: { default: 1.0, min: 0.0, max: 10.0, step: 0.1 }, | |
| 24 | - pitch: 1.0, | |
| 24 | + pitch: { default: 0, min: -12, max: 12, step: 1 }, | |
| 25 | 25 | audioSampleRate: 32000, |
| 26 | 26 | bitrate: 128000, |
| 27 | 27 | format: 'mp3', |
| @@ -84,15 +84,15 @@ class MiniMaxTtsProvider { | ||
| 84 | 84 | |
| 85 | 85 | <div class="tts_block"> |
| 86 | 86 | <label for="minimax_tts_speed">Speed: <span id="minimax_tts_speed_output"></span></label> |
| 87 | 87 | <input id="minimax_tts_speed" type="range" value="${this.defaultSettings.speed.default}" min="0${this.5defaultSettings.speed.min}" max="2${this.0defaultSettings.speed.max}" step="0${this.1defaultSettings.speed.step}" /> |
| 88 | 88 | </div> |
| 89 | 89 | <div class="tts_block"> |
| 90 | 90 | <label for="minimax_tts_volume">Volume: <span id="minimax_tts_volume_output"></span></label> |
| 91 | 91 | <input id="minimax_tts_volume" type="range" value="${this.defaultSettings.volume.default}" min="0${this.1defaultSettings.volume.min}" max="2${this.0defaultSettings.volume.max}" step="0${this.1defaultSettings.volume.step}" /> |
| 92 | 92 | </div> |
| 93 | 93 | <div class="tts_block"> |
| 94 | 94 | <label for="minimax_tts_pitch">Pitch: <span id="minimax_tts_pitch_output"></span></label> |
| 95 | 95 | <input id="minimax_tts_pitch" type="range" value="${this.defaultSettings.pitch.default}" min="0${this.5defaultSettings.pitch.min}" max="2${this.0defaultSettings.pitch.max}" step="0${this.1defaultSettings.pitch.step}" /> |
| 96 | 96 | </div> |
| 97 | 97 | <div class="tts_block"> |
| 98 | 98 | <label for="minimax_tts_format">Audio Format</label> |
| @@ -190,14 +190,14 @@ class MiniMaxTtsProvider { | ||
| 190 | 190 | this.settings.apiHost = $('#minimax_tts_api_host').val(); |
| 191 | 191 | this.settings.speed = parseFloat($('#minimax_tts_speed').val().toString()); |
| 192 | 192 | this.settings.volume = parseFloat($('#minimax_tts_volume').val().toString()); |
| 193 | 193 | this.settings.pitch = parseFloatparseInt($('#minimax_tts_pitch').val().toString()); |
| 194 | 194 | this.settings.model = $('#minimax_tts_model').find(':selected').val(); |
| 195 | 195 | this.settings.format = $('#minimax_tts_format').find(':selected').val(); |
| 196 | 196 | this.settings.customVoiceId = $('#minimax_tts_custom_voice_id').val(); |
| 197 | 197 | |
| 198 | 198 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); |
| 199 | 199 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); |
| 200 | 200 | $('#minimax_tts_pitch_output').text(this.settings.pitch.toFixed(1)); |
| 201 | 201 | |
| 202 | 202 | saveTtsProviderSettings(); |
| 203 | 203 | } |
| @@ -458,6 +458,16 @@ class MiniMaxTtsProvider { | ||
| 458 | 458 | // Only accept keys defined in defaultSettings |
| 459 | 459 | this.settings = { ...this.defaultSettings }; |
| 460 | 460 | |
| 461 | + // Flatten the settings fields with default/min/max definitions so the actual values are used | |
| 462 | + this.settings = Object.fromEntries( | |
| 463 | + Object.entries(this.defaultSettings).map(([key, value]) => { | |
| 464 | + if (value && typeof value === 'object' && 'default' in value) { | |
| 465 | + return [key, value.default]; | |
| 466 | + } | |
| 467 | + return [key, value]; | |
| 468 | + }), | |
| 469 | + ); | |
| 470 | + | |
| 461 | 471 | for (const key in settings) { |
| 462 | 472 | if (key in this.settings) { |
| 463 | 473 | this.settings[key] = settings[key]; |
| @@ -470,6 +480,21 @@ class MiniMaxTtsProvider { | ||
| 470 | 480 | if (!this.settings.customModels) this.settings.customModels = []; |
| 471 | 481 | if (!this.settings.customVoices) this.settings.customVoices = []; |
| 472 | 482 | |
| 483 | + // # Migrate settings | |
| 484 | + // Pitch value changed from float to int. If it's a float, let's try to extrapolate it to the new range | |
| 485 | + if (!Number.isInteger(this.settings.pitch)) { | |
| 486 | + const oldPitch = parseFloat(this.settings.pitch); | |
| 487 | + if (!isNaN(oldPitch)) { | |
| 488 | + // map old [0.5..1.0] to [-12..0], and [1.0..2.0] to [0..12] (old default was 1.0, new default is 0) | |
| 489 | + const newPitch = (oldPitch < 1.0) ? (oldPitch - 1.0) * 24 : (oldPitch - 1.0) * 12; | |
| 490 | + this.settings.pitch = Math.max(-12, Math.min(12, Math.round(newPitch))); | |
| 491 | + console.info(`MiniMax TTS: Migrated pitch from ${oldPitch} to ${this.settings.pitch}`); | |
| 492 | + } else { | |
| 493 | + this.settings.pitch = 0; | |
| 494 | + console.info(`MiniMax TTS: Migration reset pitch to default ${this.settings.pitch}`); | |
| 495 | + } | |
| 496 | + } | |
| 497 | + | |
| 473 | 498 | $('#minimax_tts_api_host').val(this.settings.apiHost || 'https://api.minimax.io'); |
| 474 | 499 | $('#minimax_tts_model').val(this.settings.model); |
| 475 | 500 | $('#minimax_tts_speed').val(this.settings.speed); |
| @@ -546,7 +571,7 @@ class MiniMaxTtsProvider { | ||
| 546 | 571 | |
| 547 | 572 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); |
| 548 | 573 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); |
| 549 | 574 | $('#minimax_tts_pitch_output').text(this.settings.pitch.toFixed(1)); |
| 550 | 575 | |
| 551 | 576 | // Initialize custom configuration display |
| 552 | 577 | this.updateCustomModelsDisplay(); |
| @@ -756,17 +781,20 @@ class MiniMaxTtsProvider { | ||
| 756 | 781 | throw error; |
| 757 | 782 | } |
| 758 | 783 | |
| 784 | + /** @param {number} number @param {number} lower @param {number} upper @returns {number} */ | |
| 785 | + const clamp = (number, lower, upper) => Math.min(Math.max(number, lower), upper); | |
| 786 | + | |
| 759 | 787 | const requestBody = { |
| 760 | 788 | text: inputText, |
| 761 | 789 | voiceId: voiceId, |
| 762 | 790 | apiHost: this.settings.apiHost, |
| 763 | 791 | model: this.settings.model || 'speech-02-hd'this.defaultSettings.model, |
| 764 | 792 | speed: clamp(Number(this.settings.speed) || 1this.0defaultSettings.speed.default, this.defaultSettings.speed.min, this.defaultSettings.speed.max), |
| 765 | 793 | volume: clamp(Number(this.settings.volume) || 1this.0defaultSettings.volume.default, this.defaultSettings.volume.min, this.defaultSettings.volume.max), |
| 766 | 794 | pitch: clamp(Math.round(Number(this.settings.pitch)) || 1this.0defaultSettings.pitch.default, this.defaultSettings.pitch.min, this.defaultSettings.pitch.max), |
| 767 | 795 | audioSampleRate: Number(this.settings.audioSampleRate) || 32000this.defaultSettings.audioSampleRate, |
| 768 | 796 | bitrate: Number(this.settings.bitrate) || 128000this.defaultSettings.bitrate, |
| 769 | 797 | format: this.settings.format || 'mp3'this.defaultSettings.format, |
| 770 | 798 | language: language, |
| 771 | 799 | }; |
| 772 | 800 | |