feat: Kokoro voice blending — blend builder UI + weighted tensor synthesis
Add voice blend support to TTS pipeline and settings UI. Users can mix 2–5 Kokoro voices with per-voice weight sliders; the blended style tensor replaces the single voice when enabled. Settings persist as JSON and auto- load on synthesis when no explicit voice is supplied in the request. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -639,6 +639,11 @@ export interface VoiceEntry {
|
||||
label: string
|
||||
}
|
||||
|
||||
export interface VoiceBlendEntry {
|
||||
voice: string
|
||||
weight: number
|
||||
}
|
||||
|
||||
export const getVoiceStatus = () => apiGet<VoiceStatusResult>('/api/voice/status')
|
||||
|
||||
export const getVoiceList = () =>
|
||||
@@ -658,12 +663,19 @@ export async function transcribeAudio(blob: Blob): Promise<{ transcript: string;
|
||||
export async function synthesiseSpeech(
|
||||
text: string,
|
||||
voice?: string,
|
||||
speed?: number
|
||||
speed?: number,
|
||||
voiceBlend?: VoiceBlendEntry[]
|
||||
): Promise<Blob> {
|
||||
const body: Record<string, unknown> = { text, speed: speed ?? 1.0 }
|
||||
if (voiceBlend && voiceBlend.length >= 2) {
|
||||
body.voice_blend = voiceBlend
|
||||
} else {
|
||||
body.voice = voice ?? 'af_heart'
|
||||
}
|
||||
const res = await fetch('/api/voice/synthesise', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text, voice: voice ?? 'af_heart', speed: speed ?? 1.0 }),
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }))
|
||||
|
||||
Reference in New Issue
Block a user