Browse Source

add timeout

drawing-pad
Stephanie Gredell 1 month ago
parent
commit
4fae2bb2b2
  1. 22
      backend/src/controllers/speechSounds.controller.ts
  2. 12
      backend/src/services/elevenlabs.service.ts

22
backend/src/controllers/speechSounds.controller.ts

@ -77,8 +77,8 @@ export async function pronounceWord(req: AuthRequest, res: Response) {
try { try {
const { audio, format } = await generateSpeech(wordText, voiceId); const { audio, format } = await generateSpeech(wordText, voiceId);
// Store in cache // Store in cache (don't await - cache in background to return faster)
await db.execute({ db.execute({
sql: ` sql: `
INSERT INTO word_pronunciations (word_id, voice_id, audio_data, audio_format) INSERT INTO word_pronunciations (word_id, voice_id, audio_data, audio_format)
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
@ -88,9 +88,12 @@ export async function pronounceWord(req: AuthRequest, res: Response) {
created_at = CURRENT_TIMESTAMP created_at = CURRENT_TIMESTAMP
`, `,
args: [wordId, voiceId, audio, format] args: [wordId, voiceId, audio, format]
}).catch(err => {
console.error('Error caching pronunciation:', err);
// Don't fail the request if caching fails
}); });
// Return audio // Return audio immediately
const contentType = format === 'mp3' ? 'audio/mpeg' : const contentType = format === 'mp3' ? 'audio/mpeg' :
format === 'wav' ? 'audio/wav' : format === 'wav' ? 'audio/wav' :
format === 'ogg' ? 'audio/ogg' : 'audio/mpeg'; format === 'ogg' ? 'audio/ogg' : 'audio/mpeg';
@ -113,11 +116,22 @@ export async function pronounceWord(req: AuthRequest, res: Response) {
}); });
} }
// Handle timeout errors
if (error.message.includes('timed out')) {
return res.status(504).json({
success: false,
error: {
code: 'SPEECH_GENERATION_TIMEOUT',
message: 'Speech generation timed out. Please try again.'
}
});
}
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
error: { error: {
code: 'SPEECH_GENERATION_ERROR', code: 'SPEECH_GENERATION_ERROR',
message: 'Failed to generate speech pronunciation' message: error.message || 'Failed to generate speech pronunciation'
} }
}); });
} }

12
backend/src/services/elevenlabs.service.ts

@ -27,6 +27,10 @@ export async function generateSpeech(
} }
try { try {
// Add timeout to prevent gateway timeouts (30 seconds)
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000);
const response = await fetch(`${ELEVENLABS_API_URL}/text-to-speech/${voiceId}`, { const response = await fetch(`${ELEVENLABS_API_URL}/text-to-speech/${voiceId}`, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -38,9 +42,12 @@ export async function generateSpeech(
text: text.trim(), text: text.trim(),
model_id: 'eleven_turbo_v2_5' model_id: 'eleven_turbo_v2_5'
// No voice_settings - uses the voice's default settings from ElevenLabs // No voice_settings - uses the voice's default settings from ElevenLabs
}) }),
signal: controller.signal
}); });
clearTimeout(timeoutId);
if (!response.ok) { if (!response.ok) {
const errorText = await response.text(); const errorText = await response.text();
console.error('ElevenLabs API error:', response.status, errorText); console.error('ElevenLabs API error:', response.status, errorText);
@ -65,6 +72,9 @@ export async function generateSpeech(
format format
}; };
} catch (error: any) { } catch (error: any) {
if (error.name === 'AbortError') {
throw new Error('ElevenLabs API request timed out after 30 seconds');
}
if (error.message.includes('ElevenLabs API error')) { if (error.message.includes('ElevenLabs API error')) {
throw error; throw error;
} }

Loading…
Cancel
Save