Fix LiteLLM STT: use axios directly instead of OpenAI SDK

OpenAI SDK's audio.transcriptions.create() hangs with LiteLLM
(no timeout, SDK-level incompatibility with multipart handling).
Use axios + form-data directly with 120s timeout — same approach
as ElevenLabs TTS. Handles both {text:"..."} and plain string responses.
This commit is contained in:
Daniel Onyejesi 2026-03-29 21:32:30 -04:00
parent f8d865a0a9
commit ce7d0e749d

View file

@ -69,17 +69,27 @@ router.post('/transcribe', authMiddleware, upload.single('audio'), async (req, r
} }
if (provider === 'litellm') { if (provider === 'litellm') {
if (!litellmClient) return res.status(400).json({ error: 'LiteLLM not configured. Set LITELLM_API_BASE.' }); if (!process.env.LITELLM_API_BASE) return res.status(400).json({ error: 'LITELLM_API_BASE not set.' });
var sttModel = process.env.LITELLM_STT_MODEL || 'whisper-1'; var sttModel = process.env.LITELLM_STT_MODEL || 'whisper-1';
var file = new File([req.file.buffer], 'audio.webm', { type: req.file.mimetype || 'audio/webm' }); var FormData = require('form-data');
var result = await litellmClient.audio.transcriptions.create({ var axios = require('axios');
file: file, var form = new FormData();
model: sttModel, form.append('file', req.file.buffer, {
language: 'en', filename: 'audio.webm',
response_format: 'text', contentType: req.file.mimetype || 'audio/webm'
prompt: 'Medical patient encounter. Pediatric. Clinical terms, diagnoses, medications.'
}); });
var text = typeof result === 'string' ? result : result.text; form.append('model', sttModel);
form.append('language', 'en');
form.append('response_format', 'json');
form.append('prompt', 'Medical patient encounter. Pediatric. Clinical terms, diagnoses, medications.');
var sttHeaders = Object.assign({}, form.getHeaders());
if (process.env.LITELLM_API_KEY) sttHeaders['Authorization'] = 'Bearer ' + process.env.LITELLM_API_KEY;
var base = process.env.LITELLM_API_BASE.replace(/\/+$/, '');
var sttResp = await axios.post(base + '/v1/audio/transcriptions', form, {
headers: sttHeaders,
timeout: 120000
});
var text = (sttResp.data && sttResp.data.text) ? sttResp.data.text : String(sttResp.data || '');
console.log('[Transcribe] LiteLLM (' + sttModel + ') done in ' + (Date.now() - startTime) + 'ms'); console.log('[Transcribe] LiteLLM (' + sttModel + ') done in ' + (Date.now() - startTime) + 'ms');
return res.json({ success: true, text: text, provider: 'litellm-stt', duration: Date.now() - startTime }); return res.json({ success: true, text: text, provider: 'litellm-stt', duration: Date.now() - startTime });
} }