- Add GET /api/transcribe/status endpoint — returns whether any server transcription provider (Whisper/AWS/Local) is configured - Frontend checks status on login via checkTranscribeStatus() - When no provider configured: recording stops instantly, keeps live Web Speech API text, shows friendly toast — no error, no upload wait - Works in encounter, dictation, and SOAP tabs - App now works fully out-of-the-box with just an AI provider key
83 lines
3.9 KiB
JavaScript
83 lines
3.9 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const multer = require('multer');
|
|
const { whisperClient } = require('../utils/ai');
|
|
const { transcribeWithAWS, isAWSTranscribeConfigured } = require('../utils/transcribeAWS');
|
|
const { transcribeWithLocal, isLocalWhisperConfigured } = require('../utils/transcribeLocal');
|
|
const { authMiddleware } = require('../middleware/auth');
|
|
|
|
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 25 * 1024 * 1024 } });
|
|
|
|
// Determine which provider to use:
|
|
// TRANSCRIBE_PROVIDER=aws → always use Amazon Transcribe
|
|
// TRANSCRIBE_PROVIDER=openai → always use OpenAI Whisper
|
|
// (default) if AWS Bedrock region is set → use AWS Transcribe
|
|
// otherwise → use OpenAI Whisper
|
|
function getTranscribeProvider() {
|
|
var env = process.env.TRANSCRIBE_PROVIDER;
|
|
if (env === 'local') return 'local';
|
|
if (env === 'aws') return 'aws';
|
|
if (env === 'openai') return 'openai';
|
|
// Auto-detect: prefer AWS when Bedrock is already configured
|
|
if (isAWSTranscribeConfigured()) return 'aws';
|
|
return 'openai';
|
|
}
|
|
|
|
// Check if any transcription provider is actually available
|
|
function isTranscribeAvailable() {
|
|
if (isLocalWhisperConfigured()) return true;
|
|
if (isAWSTranscribeConfigured()) return true;
|
|
if (whisperClient) return true;
|
|
return false;
|
|
}
|
|
|
|
var provider = getTranscribeProvider();
|
|
var medical = process.env.AWS_TRANSCRIBE_MEDICAL === 'true';
|
|
var available = isTranscribeAvailable();
|
|
console.log('🎙️ Transcribe provider:', provider + (provider === 'aws' && medical ? ' (Medical)' : '') + (available ? '' : ' (NOT CONFIGURED — browser speech only)'));
|
|
|
|
// Status endpoint — frontend checks this to decide whether to upload audio
|
|
router.get('/transcribe/status', authMiddleware, (req, res) => {
|
|
res.json({ available: available, provider: available ? provider : 'none' });
|
|
});
|
|
|
|
router.post('/transcribe', authMiddleware, upload.single('audio'), async (req, res) => {
|
|
try {
|
|
if (!req.file) return res.status(400).json({ error: 'No audio' });
|
|
var startTime = Date.now();
|
|
var fileSize = req.file.size;
|
|
console.log('[Transcribe] Received ' + (fileSize / 1024).toFixed(0) + 'KB audio (' + (req.file.mimetype || 'unknown') + ') via ' + provider);
|
|
|
|
if (provider === 'local') {
|
|
var text = await transcribeWithLocal(req.file.buffer, req.file.mimetype || 'audio/webm');
|
|
console.log('[Transcribe] Local done in ' + (Date.now() - startTime) + 'ms');
|
|
return res.json({ success: true, text: text, provider: 'local-whisper', duration: Date.now() - startTime });
|
|
}
|
|
|
|
if (provider === 'aws') {
|
|
if (!isAWSTranscribeConfigured()) {
|
|
return res.status(400).json({ error: 'AWS Transcribe not configured. Set AWS_BEDROCK_REGION.' });
|
|
}
|
|
var text = await transcribeWithAWS(req.file.buffer, req.file.mimetype || 'audio/webm');
|
|
console.log('[Transcribe] AWS done in ' + (Date.now() - startTime) + 'ms');
|
|
return res.json({ success: true, text: text, provider: 'aws-transcribe', duration: Date.now() - startTime });
|
|
}
|
|
|
|
// OpenAI Whisper
|
|
if (!whisperClient) return res.status(400).json({ error: 'Whisper not configured. Set OPENAI_API_KEY.' });
|
|
var file = new File([req.file.buffer], 'audio.webm', { type: req.file.mimetype || 'audio/webm' });
|
|
var result = await whisperClient.audio.transcriptions.create({
|
|
file, model: 'whisper-1', language: 'en',
|
|
response_format: 'text',
|
|
prompt: 'Medical patient encounter. Pediatric. Clinical terms, diagnoses, medications.'
|
|
});
|
|
var text = typeof result === 'string' ? result : result.text;
|
|
console.log('[Transcribe] Whisper done in ' + (Date.now() - startTime) + 'ms');
|
|
res.json({ success: true, text: text, provider: 'openai-whisper', duration: Date.now() - startTime });
|
|
} catch (err) {
|
|
console.error('[Transcribe] Error:', err.message);
|
|
res.status(500).json({ error: err.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|