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 | .minimax-custom-item { | 6 | .minimax-custom-item { |
| 2 | display: flex; | 7 | display: flex; |
| 3 | justify-content: space-between; | 8 | justify-content: space-between; |
| @@ -19,9 +19,9 @@ class MiniMaxTtsProvider { | |||
| 19 | apiHost: 'https://api.minimax.io', | 19 | apiHost: 'https://api.minimax.io', |
| 20 | model: 'speech-02-hd', | 20 | model: 'speech-02-hd', |
| 21 | voiceMap: {}, | 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 | audioSampleRate: 32000, | 25 | audioSampleRate: 32000, |
| 26 | bitrate: 128000, | 26 | bitrate: 128000, |
| 27 | format: 'mp3', | 27 | format: 'mp3', |
| @@ -84,15 +84,15 @@ class MiniMaxTtsProvider { | |||
| 84 | 84 | ||
| 85 | <div class="tts_block"> | 85 | <div class="tts_block"> |
| 86 | <label for="minimax_tts_speed">Speed: <span id="minimax_tts_speed_output"></span></label> | 86 | <label for="minimax_tts_speed">Speed: <span id="minimax_tts_speed_output"></span></label> |
| 87 | <input id="minimax_tts_speed" type="range" value="${this.defaultSettings.speed}" min="0.5" max="2.0" step="0.1" /> | 87 | <input id="minimax_tts_speed" type="range" value="${this.defaultSettings.speed.default}" min="${this.defaultSettings.speed.min}" max="${this.defaultSettings.speed.max}" step="${this.defaultSettings.speed.step}" /> |
| 88 | </div> | 88 | </div> |
| 89 | <div class="tts_block"> | 89 | <div class="tts_block"> |
| 90 | <label for="minimax_tts_volume">Volume: <span id="minimax_tts_volume_output"></span></label> | 90 | <label for="minimax_tts_volume">Volume: <span id="minimax_tts_volume_output"></span></label> |
| 91 | <input id="minimax_tts_volume" type="range" value="${this.defaultSettings.volume}" min="0.1" max="2.0" step="0.1" /> | 91 | <input id="minimax_tts_volume" type="range" value="${this.defaultSettings.volume.default}" min="${this.defaultSettings.volume.min}" max="${this.defaultSettings.volume.max}" step="${this.defaultSettings.volume.step}" /> |
| 92 | </div> | 92 | </div> |
| 93 | <div class="tts_block"> | 93 | <div class="tts_block"> |
| 94 | <label for="minimax_tts_pitch">Pitch: <span id="minimax_tts_pitch_output"></span></label> | 94 | <label for="minimax_tts_pitch">Pitch: <span id="minimax_tts_pitch_output"></span></label> |
| 95 | <input id="minimax_tts_pitch" type="range" value="${this.defaultSettings.pitch}" min="0.5" max="2.0" step="0.1" /> | 95 | <input id="minimax_tts_pitch" type="range" value="${this.defaultSettings.pitch.default}" min="${this.defaultSettings.pitch.min}" max="${this.defaultSettings.pitch.max}" step="${this.defaultSettings.pitch.step}" /> |
| 96 | </div> | 96 | </div> |
| 97 | <div class="tts_block"> | 97 | <div class="tts_block"> |
| 98 | <label for="minimax_tts_format">Audio Format</label> | 98 | <label for="minimax_tts_format">Audio Format</label> |
| @@ -190,14 +190,14 @@ class MiniMaxTtsProvider { | |||
| 190 | this.settings.apiHost = $('#minimax_tts_api_host').val(); | 190 | this.settings.apiHost = $('#minimax_tts_api_host').val(); |
| 191 | this.settings.speed = parseFloat($('#minimax_tts_speed').val().toString()); | 191 | this.settings.speed = parseFloat($('#minimax_tts_speed').val().toString()); |
| 192 | this.settings.volume = parseFloat($('#minimax_tts_volume').val().toString()); | 192 | this.settings.volume = parseFloat($('#minimax_tts_volume').val().toString()); |
| 193 | this.settings.pitch = parseFloat($('#minimax_tts_pitch').val().toString()); | 193 | this.settings.pitch = parseInt($('#minimax_tts_pitch').val().toString()); |
| 194 | this.settings.model = $('#minimax_tts_model').find(':selected').val(); | 194 | this.settings.model = $('#minimax_tts_model').find(':selected').val(); |
| 195 | this.settings.format = $('#minimax_tts_format').find(':selected').val(); | 195 | this.settings.format = $('#minimax_tts_format').find(':selected').val(); |
| 196 | this.settings.customVoiceId = $('#minimax_tts_custom_voice_id').val(); | 196 | this.settings.customVoiceId = $('#minimax_tts_custom_voice_id').val(); |
| 197 | 197 | ||
| 198 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); | 198 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); |
| 199 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); | 199 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); |
| 200 | $('#minimax_tts_pitch_output').text(this.settings.pitch.toFixed(1)); | 200 | $('#minimax_tts_pitch_output').text(this.settings.pitch); |
| 201 | 201 | ||
| 202 | saveTtsProviderSettings(); | 202 | saveTtsProviderSettings(); |
| 203 | } | 203 | } |
| @@ -458,6 +458,16 @@ class MiniMaxTtsProvider { | |||
| 458 | // Only accept keys defined in defaultSettings | 458 | // Only accept keys defined in defaultSettings |
| 459 | this.settings = { ...this.defaultSettings }; | 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 | for (const key in settings) { | 471 | for (const key in settings) { |
| 462 | if (key in this.settings) { | 472 | if (key in this.settings) { |
| 463 | this.settings[key] = settings[key]; | 473 | this.settings[key] = settings[key]; |
| @@ -470,6 +480,21 @@ class MiniMaxTtsProvider { | |||
| 470 | if (!this.settings.customModels) this.settings.customModels = []; | 480 | if (!this.settings.customModels) this.settings.customModels = []; |
| 471 | if (!this.settings.customVoices) this.settings.customVoices = []; | 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 | $('#minimax_tts_api_host').val(this.settings.apiHost || 'https://api.minimax.io'); | 498 | $('#minimax_tts_api_host').val(this.settings.apiHost || 'https://api.minimax.io'); |
| 474 | $('#minimax_tts_model').val(this.settings.model); | 499 | $('#minimax_tts_model').val(this.settings.model); |
| 475 | $('#minimax_tts_speed').val(this.settings.speed); | 500 | $('#minimax_tts_speed').val(this.settings.speed); |
| @@ -546,7 +571,7 @@ class MiniMaxTtsProvider { | |||
| 546 | 571 | ||
| 547 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); | 572 | $('#minimax_tts_speed_output').text(this.settings.speed.toFixed(1)); |
| 548 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); | 573 | $('#minimax_tts_volume_output').text(this.settings.volume.toFixed(1)); |
| 549 | $('#minimax_tts_pitch_output').text(this.settings.pitch.toFixed(1)); | 574 | $('#minimax_tts_pitch_output').text(this.settings.pitch); |
| 550 | 575 | ||
| 551 | // Initialize custom configuration display | 576 | // Initialize custom configuration display |
| 552 | this.updateCustomModelsDisplay(); | 577 | this.updateCustomModelsDisplay(); |
| @@ -756,17 +781,20 @@ class MiniMaxTtsProvider { | |||
| 756 | throw error; | 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 | const requestBody = { | 787 | const requestBody = { |
| 760 | text: inputText, | 788 | text: inputText, |
| 761 | voiceId: voiceId, | 789 | voiceId: voiceId, |
| 762 | apiHost: this.settings.apiHost, | 790 | apiHost: this.settings.apiHost, |
| 763 | model: this.settings.model || 'speech-02-hd', | 791 | model: this.settings.model || this.defaultSettings.model, |
| 764 | speed: Number(this.settings.speed) || 1.0, | 792 | speed: clamp(Number(this.settings.speed) || this.defaultSettings.speed.default, this.defaultSettings.speed.min, this.defaultSettings.speed.max), |
| 765 | volume: Number(this.settings.volume) || 1.0, | 793 | volume: clamp(Number(this.settings.volume) || this.defaultSettings.volume.default, this.defaultSettings.volume.min, this.defaultSettings.volume.max), |
| 766 | pitch: Number(this.settings.pitch) || 1.0, | 794 | pitch: clamp(Math.round(Number(this.settings.pitch)) || this.defaultSettings.pitch.default, this.defaultSettings.pitch.min, this.defaultSettings.pitch.max), |
| 767 | audioSampleRate: Number(this.settings.audioSampleRate) || 32000, | 795 | audioSampleRate: Number(this.settings.audioSampleRate) || this.defaultSettings.audioSampleRate, |
| 768 | bitrate: Number(this.settings.bitrate) || 128000, | 796 | bitrate: Number(this.settings.bitrate) || this.defaultSettings.bitrate, |
| 769 | format: this.settings.format || 'mp3', | 797 | format: this.settings.format || this.defaultSettings.format, |
| 770 | language: language, | 798 | language: language, |
| 771 | }; | 799 | }; |
| 772 | 800 | ||