feat: add Edge TTS rate/pitch sliders to voice settings (#629)

Add speed (rate) and pitch controls for Edge TTS provider:
- Frontend: speedToEdgeRate()/hzToEdgePitch() helpers + UI sliders
- Backend: rate/pitch passthrough in OpenaiTtsRequest and controller
- i18n: add edgeRate/edgePitch keys across all 8 languages
- Rate: 0.5x-2.0x slider, Pitch: -20Hz to +20Hz slider
This commit is contained in:
memeflyfly
2026-05-11 21:56:11 +08:00
committed by GitHub
parent 5e608ea338
commit a68b9bf01f
16 changed files with 142 additions and 4 deletions
@@ -11,6 +11,8 @@ export interface OpenaiTtsOptions {
apiKey?: string
model?: string
voice?: string
rate?: string // Edge TTS rate format, e.g. "+20%"
pitch?: string // Edge TTS pitch format, e.g. "-8Hz"
}
export interface SpeechState {
@@ -266,6 +268,9 @@ export function useSpeech() {
input: text,
voice: opts.voice || 'alloy',
}
// Edge TTS proxy 支持 rate/pitch 参数
if (opts.rate) body.rate = opts.rate
if (opts.pitch) body.pitch = opts.pitch
const headers: Record<string, string> = {
'Content-Type': 'application/json',
@@ -21,6 +21,8 @@ export interface VoiceSettingsData {
// Edge TTS
edgeUrl: string
edgeVoice: string
edgeRate: number // 语速倍率 0.5~2.01.0 = 正常
edgePitchHz: number // 音调偏移 Hz-20~200 = 正常
}
const STORAGE_KEY = 'hermes-tts-settings-v2'
@@ -63,6 +65,8 @@ const DEFAULT: VoiceSettingsData = {
edgeUrl: '',
edgeVoice: 'zh-CN-XiaoxiaoNeural',
edgeRate: 1.0,
edgePitchHz: 0,
}
function sanitize(data: VoiceSettingsData): VoiceSettingsData {
@@ -103,11 +107,13 @@ const customApiKey = ref<string>(load().customApiKey)
// Edge TTS
const edgeUrl = ref<string>(load().edgeUrl)
const edgeVoice = ref<string>(load().edgeVoice)
const edgeRate = ref<number>(load().edgeRate)
const edgePitchHz = ref<number>(load().edgePitchHz)
// Auto-persist on change
watch(
[provider, webspeechVoice, openaiApiKey, openaiBaseUrl, openaiModel, openaiVoice,
customUrl, customApiKey, edgeUrl, edgeVoice],
customUrl, customApiKey, edgeUrl, edgeVoice, edgeRate, edgePitchHz],
() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
provider: provider.value,
@@ -120,6 +126,8 @@ watch(
customApiKey: customApiKey.value,
edgeUrl: edgeUrl.value,
edgeVoice: edgeVoice.value,
edgeRate: edgeRate.value,
edgePitchHz: edgePitchHz.value,
}))
},
)
@@ -136,6 +144,8 @@ export function useVoiceSettings() {
customApiKey,
edgeUrl,
edgeVoice,
edgeRate,
edgePitchHz,
setProvider(v: TtsProvider) { provider.value = v },
setWebSpeechVoice(v: string) { webspeechVoice.value = v },
@@ -147,6 +157,8 @@ export function useVoiceSettings() {
setCustomApiKey(v: string) { customApiKey.value = v },
setEdgeUrl(v: string) { edgeUrl.value = v },
setEdgeVoice(v: string) { edgeVoice.value = v },
setEdgeRate(v: number) { edgeRate.value = v },
setEdgePitchHz(v: number) { edgePitchHz.value = v },
reset() {
provider.value = DEFAULT.provider
@@ -159,6 +171,8 @@ export function useVoiceSettings() {
customApiKey.value = DEFAULT.customApiKey
edgeUrl.value = DEFAULT.edgeUrl
edgeVoice.value = DEFAULT.edgeVoice
edgeRate.value = DEFAULT.edgeRate
edgePitchHz.value = DEFAULT.edgePitchHz
},
}
}