a68b9bf01f
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
71 lines
1.6 KiB
TypeScript
71 lines
1.6 KiB
TypeScript
import type { Context } from 'koa'
|
|
import { textToSpeech, openaiCompatibleTts, speedToEdgeRate } from '../../services/hermes/tts'
|
|
|
|
export async function generate(ctx: Context) {
|
|
const { text, lang } = ctx.request.body as {
|
|
text?: string
|
|
lang?: string
|
|
}
|
|
|
|
if (!text || typeof text !== 'string') {
|
|
ctx.status = 400
|
|
ctx.body = { error: 'text is required' }
|
|
return
|
|
}
|
|
|
|
if (text.length > 5000) {
|
|
ctx.status = 400
|
|
ctx.body = { error: 'text is too long (max 5000 characters)' }
|
|
return
|
|
}
|
|
|
|
const { audio, engine } = await textToSpeech({ text, lang })
|
|
|
|
ctx.set('Content-Type', 'audio/mpeg')
|
|
ctx.set('Content-Length', String(audio.length))
|
|
ctx.set('X-TTS-Engine', engine)
|
|
ctx.body = audio
|
|
}
|
|
|
|
/**
|
|
* OpenAI-compatible TTS endpoint.
|
|
* Accepts: { model, input, voice, speed }
|
|
* Returns audio/mpeg stream.
|
|
*/
|
|
export async function openaiProxy(ctx: Context) {
|
|
const body = ctx.request.body as {
|
|
input?: string
|
|
voice?: string
|
|
speed?: number
|
|
model?: string
|
|
rate?: string
|
|
pitch?: string
|
|
}
|
|
|
|
if (!body.input || typeof body.input !== 'string') {
|
|
ctx.status = 400
|
|
ctx.body = { error: 'input is required' }
|
|
return
|
|
}
|
|
|
|
if (body.input.length > 5000) {
|
|
ctx.status = 400
|
|
ctx.body = { error: 'input is too long (max 5000 characters)' }
|
|
return
|
|
}
|
|
|
|
const { audio, engine } = await openaiCompatibleTts({
|
|
input: body.input,
|
|
voice: body.voice,
|
|
speed: body.speed,
|
|
model: body.model,
|
|
rate: body.rate,
|
|
pitch: body.pitch,
|
|
})
|
|
|
|
ctx.set('Content-Type', 'audio/mpeg')
|
|
ctx.set('Content-Length', String(audio.length))
|
|
ctx.set('X-TTS-Engine', engine)
|
|
ctx.body = audio
|
|
}
|