| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253 |
- const KEY = import.meta.env.VITE_AZURE_SPEECH_KEY as string | undefined
- const REGION = import.meta.env.VITE_AZURE_SPEECH_REGION as string | undefined
- const VOICE = 'en-US-AriaNeural'
- const FORMAT = 'audio-24khz-48kbitrate-mono-mp3'
- /**
- * Synthesize English text via Azure Speech REST.
- * Returns an MP3 Blob. Throws on credential / network / non-2xx.
- *
- * Pass an AbortSignal so callers (the audio player) can cancel
- * an in-flight synthesis when the user starts recording or
- * triggers a different playback.
- */
- export async function synthesize(text: string, signal?: AbortSignal): Promise<Blob> {
- if (!KEY || !REGION) {
- throw new Error('Azure Speech credentials not configured (VITE_AZURE_SPEECH_KEY / VITE_AZURE_SPEECH_REGION)')
- }
- const ssml =
- `<speak version='1.0' xml:lang='en-US'>` +
- `<voice name='${VOICE}'>${escapeXml(text)}</voice>` +
- `</speak>`
- const res = await fetch(
- `https://${REGION}.tts.speech.microsoft.com/cognitiveservices/v1`,
- {
- method: 'POST',
- signal,
- headers: {
- 'Ocp-Apim-Subscription-Key': KEY,
- 'Content-Type': 'application/ssml+xml',
- 'X-Microsoft-OutputFormat': FORMAT,
- 'User-Agent': 'PPT-EnglishSpeaking',
- },
- body: ssml,
- },
- )
- if (!res.ok) {
- throw new Error(`Azure TTS failed: ${res.status} ${res.statusText}`)
- }
- return res.blob()
- }
- function escapeXml(s: string): string {
- return s.replace(/[<>&'"]/g, c => ({
- '<': '<',
- '>': '>',
- '&': '&',
- "'": ''',
- '"': '"',
- }[c]!))
- }
|