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>

d2f3a85742fd48547593076cd2f336402ee06b6b

Wolfsblvt <wolfsblvt@gmail.com>

Signed
2 files changed, +49 -16Showing whitespace changes
public/scripts/extensions/tts/css/minimax-tts.css+5 -0
@@ -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;
public/scripts/extensions/tts/minimax.js+44 -16
@@ -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 {
8484
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();
197197
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);
201201
202 saveTtsProviderSettings();202 saveTtsProviderSettings();
203 }203 }
@@ -458,6 +458,16 @@ class MiniMaxTtsProvider {
458 // Only accept keys defined in defaultSettings458 // Only accept keys defined in defaultSettings
459 this.settings = { ...this.defaultSettings };459 this.settings = { ...this.defaultSettings };
460460
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 = [];
472482
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 {
546571
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);
550575
551 // Initialize custom configuration display576 // Initialize custom configuration display
552 this.updateCustomModelsDisplay();577 this.updateCustomModelsDisplay();
@@ -756,17 +781,20 @@ class MiniMaxTtsProvider {
756 throw error;781 throw error;
757 }782 }
758783
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 };
772800