fix: disable SSML when not support

This commit is contained in:
RainbowBird
2026-06-14 05:03:53 +08:00
parent c3f2beba47
commit 51a44c1f54
2 changed files with 39 additions and 3 deletions
@@ -126,6 +126,39 @@ describe('speech store helpers', () => {
expect(request.input).toContain('volume="-5%"')
})
/**
* @example
* speechStore.resolveVoicePackSpeechInput({ text, voice, forceSSML: true, supportsSSML: false, supportsAdapterProsody: true })
*/
it('keeps official adapter-backed speech input as plain text when global SSML is enabled', () => {
const speechStore = useSpeechStore()
const voice = {
id: 'voice-1',
name: 'Voice 1',
provider: OFFICIAL_SPEECH_PROVIDER_ID,
languages: [{ code: 'en-US', title: 'English' }],
gender: 'neutral',
}
// ROOT CAUSE:
//
// Auto TTS can enable global SSML before the server routes the official
// speech provider to DashScope CosyVoice. DashScope rejects `<speak>...`
// payloads with `SSML text is not supported at the moment!`, so providers
// that apply prosody through adapter options must keep the text field plain.
const request = speechStore.resolveVoicePackSpeechInput({
text: 'hello',
voice,
providerConfig: { pitch: 0 },
forceSSML: true,
supportsSSML: false,
supportsAdapterProsody: true,
})
expect(request.input).toBe('hello')
expect(request.input).not.toContain('<speak')
})
/**
* @example
* speechStore.resolveVoicePackSpeechInput({ text, voice, params: { pitch: '+20%' }, supportsAdapterProsody: true })
@@ -473,10 +473,11 @@ export const useSpeechStore = defineStore('speech', () => {
function resolveVoicePackSpeechInput(options: VoicePackSpeechInputOptions): VoicePackSpeechInput {
const providerConfig = { ...options.providerConfig }
const canUseSSML = options.supportsSSML === true
if (!options.params) {
return {
input: options.forceSSML
input: options.forceSSML === true && canUseSSML
? generateSSML(options.text, options.voice, providerConfig)
: options.text,
providerConfig,
@@ -493,6 +494,8 @@ export const useSpeechStore = defineStore('speech', () => {
if (speed != null)
providerConfig.speed = speed
const shouldUseSSML = canUseSSML && (options.forceSSML === true || (needsProsody && !options.supportsAdapterProsody))
if (options.voicePack) {
providerConfig.extraBody = {
...(providerConfig.extraBody as Record<string, unknown> | undefined),
@@ -511,11 +514,11 @@ export const useSpeechStore = defineStore('speech', () => {
voice_pack: { pitch, volume },
}
}
else if (needsProsody && !options.forceSSML && !options.supportsSSML) {
else if (needsProsody && !options.supportsAdapterProsody && !shouldUseSSML) {
throw new Error('Voice Pack pitch and volume parameters require an SSML-capable speech provider.')
}
if (!options.forceSSML && (!needsProsody || options.supportsAdapterProsody)) {
if (!shouldUseSSML && (!needsProsody || options.supportsAdapterProsody)) {
return {
input: options.text,
providerConfig,