// ============================================================ // USER PREFERENCES — STT model & TTS voice selection // ============================================================ var express = require('express'); var router = express.Router(); var db = require('../db/database'); var { authMiddleware } = require('../middleware/auth'); router.use(authMiddleware); // Get current user's STT/TTS preferences router.get('/preferences', async function(req, res) { try { var user = await db.get('SELECT stt_model, tts_voice FROM users WHERE id = ?', [req.user.id]); res.json({ success: true, stt_model: user?.stt_model || null, tts_voice: user?.tts_voice || null }); } catch (err) { console.error('[Preferences]', err.message); res.status(500).json({ error: err.message }); } }); // Update user's STT/TTS preferences router.post('/preferences', async function(req, res) { try { var { stt_model, tts_voice } = req.body; await db.run( 'UPDATE users SET stt_model = ?, tts_voice = ? WHERE id = ?', [stt_model || null, tts_voice || null, req.user.id] ); res.json({ success: true }); } catch (err) { console.error('[Preferences]', err.message); res.status(500).json({ error: err.message }); } }); // Get available STT models and TTS voices router.get('/preferences/options', async function(req, res) { try { var provider = process.env.TRANSCRIBE_PROVIDER; var ttsProvider = process.env.TTS_PROVIDER; // Auto-detect providers if not explicitly set if (!provider) { if (process.env.VERTEX_PROJECT || process.env.GOOGLE_CLOUD_PROJECT) provider = 'google'; else if (process.env.AWS_BEDROCK_REGION) provider = 'aws'; else if (process.env.LITELLM_API_BASE) provider = 'litellm'; else if (process.env.OPENAI_API_KEY) provider = 'openai'; } if (!ttsProvider) { if (process.env.VERTEX_PROJECT || process.env.GOOGLE_CLOUD_PROJECT) ttsProvider = 'google'; else if (process.env.LITELLM_API_BASE) ttsProvider = 'litellm'; else if (process.env.OPENAI_API_KEY) ttsProvider = 'openai'; else if (process.env.ELEVENLABS_API_KEY) ttsProvider = 'elevenlabs'; } // STT Models var sttModels = []; if (provider === 'google') { sttModels = [ { value: 'gemini-2.0-flash-exp', label: 'Gemini 2.0 Flash (Experimental, fastest)' }, { value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash (Fast, accurate)' }, { value: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash (Stable)' }, { value: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro (Best quality, slower)' } ]; } else if (provider === 'litellm') { sttModels = [ { value: 'gemini-2.0-flash-exp', label: 'Gemini 2.0 Flash Exp' }, { value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash' }, { value: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash' }, { value: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro' }, { value: 'whisper-1', label: 'OpenAI Whisper-1' }, { value: 'whisper-large-v3', label: 'Whisper Large v3' } ]; } else if (provider === 'openai') { sttModels = [ { value: 'whisper-1', label: 'Whisper-1 (OpenAI standard)' } ]; } else if (provider === 'aws') { sttModels = [ { value: 'default', label: 'AWS Transcribe (Standard)' }, { value: 'medical', label: 'AWS Transcribe Medical' } ]; } else if (provider === 'local') { sttModels = [ { value: 'tiny', label: 'Whisper Tiny (fastest)' }, { value: 'base', label: 'Whisper Base' }, { value: 'small', label: 'Whisper Small' }, { value: 'medium', label: 'Whisper Medium' }, { value: 'large', label: 'Whisper Large (best quality)' } ]; } // TTS Voices var ttsVoices = []; if (ttsProvider === 'google') { ttsVoices = [ { value: 'en-US-Journey-F', label: 'Journey (Female, natural)' }, { value: 'en-US-Journey-D', label: 'Journey (Male, natural)' }, { value: 'en-US-Studio-O', label: 'Studio O (Female, expressive)' }, { value: 'en-US-Studio-M', label: 'Studio M (Male, expressive)' }, { value: 'en-US-Neural2-A', label: 'Neural2 A (Male, standard)' }, { value: 'en-US-Neural2-C', label: 'Neural2 C (Female, standard)' }, { value: 'en-US-Neural2-D', label: 'Neural2 D (Male, standard)' }, { value: 'en-US-Neural2-E', label: 'Neural2 E (Female, standard)' }, { value: 'en-US-Neural2-F', label: 'Neural2 F (Female, standard)' }, { value: 'en-US-Neural2-G', label: 'Neural2 G (Female, standard)' }, { value: 'en-US-Neural2-H', label: 'Neural2 H (Female, standard)' }, { value: 'en-US-Neural2-I', label: 'Neural2 I (Male, standard)' }, { value: 'en-US-Neural2-J', label: 'Neural2 J (Male, standard)' } ]; } else if (ttsProvider === 'litellm' || ttsProvider === 'openai') { ttsVoices = [ { value: 'alloy', label: 'Alloy (Neutral)' }, { value: 'echo', label: 'Echo (Male)' }, { value: 'fable', label: 'Fable (British Male)' }, { value: 'onyx', label: 'Onyx (Deep Male)' }, { value: 'nova', label: 'Nova (Female)' }, { value: 'shimmer', label: 'Shimmer (Soft Female)' } ]; } else if (ttsProvider === 'elevenlabs') { ttsVoices = [ { value: 'adam', label: 'Adam (Male, deep)' }, { value: 'rachel', label: 'Rachel (Female, calm)' }, { value: 'domi', label: 'Domi (Female, strong)' }, { value: 'bella', label: 'Bella (Female, soft)' }, { value: 'antoni', label: 'Antoni (Male, deep)' }, { value: 'elli', label: 'Elli (Female, young)' }, { value: 'josh', label: 'Josh (Male, narration)' }, { value: 'arnold', label: 'Arnold (Male, crisp)' }, { value: 'sam', label: 'Sam (Male, raspy)' } ]; } res.json({ success: true, sttProvider: provider || 'none', sttModels: sttModels, ttsProvider: ttsProvider || 'browser', ttsVoices: ttsVoices }); } catch (err) { console.error('[Preferences]', err.message); res.status(500).json({ error: err.message }); } }); module.exports = router;