54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
/**
|
|
* POST /api/coach/speak-azure
|
|
* Azure Cognitive Services TTS — de-DE-KatjaNeural
|
|
* Benötigt: AZURE_TTS_KEY + AZURE_TTS_REGION in Infisical
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
await requireUser(event);
|
|
|
|
const body = await readBody(event);
|
|
const { text } = body as { text: string };
|
|
|
|
if (!text?.trim()) {
|
|
throw createError({ statusCode: 400, message: "text fehlt" });
|
|
}
|
|
|
|
const config = useRuntimeConfig();
|
|
const key = config.azureTtsKey as string | undefined;
|
|
const region = (config.azureTtsRegion as string | undefined) || "westeurope";
|
|
|
|
if (!key) {
|
|
throw createError({ statusCode: 503, message: "Azure TTS Key nicht konfiguriert" });
|
|
}
|
|
|
|
const ssml = `<speak version='1.0' xml:lang='de-DE'>
|
|
<voice name='de-DE-KatjaNeural'>
|
|
${text.slice(0, 2000).replace(/[<>&'"]/g, (c) => ({ '<': '<', '>': '>', '&': '&', "'": ''', '"': '"' }[c] ?? c))}
|
|
</voice>
|
|
</speak>`;
|
|
|
|
const response = await fetch(
|
|
`https://${region}.tts.speech.microsoft.com/cognitiveservices/v1`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Ocp-Apim-Subscription-Key": key,
|
|
"Content-Type": "application/ssml+xml",
|
|
"X-Microsoft-OutputFormat": "audio-16khz-128kbitrate-mono-mp3",
|
|
},
|
|
body: ssml,
|
|
},
|
|
);
|
|
|
|
if (!response.ok) {
|
|
const err = await response.text();
|
|
console.error("[speak-azure] error:", response.status, err);
|
|
throw createError({ statusCode: 502, message: "Azure TTS fehlgeschlagen" });
|
|
}
|
|
|
|
const buffer = await response.arrayBuffer();
|
|
const base64 = Buffer.from(buffer).toString("base64");
|
|
|
|
return { audio: `data:audio/mp3;base64,${base64}` };
|
|
});
|