import config from '../config'; import { store } from '../utils/tempStore'; import fs from 'fs'; import path from 'path'; import { promisify } from 'util'; import axios from 'axios'; const writeFile = promisify(fs.writeFile); export interface TTSOptions { text: string; voice_id?: string; model_id?: string; stability?: number; similarity_boost?: number; } export interface TTSResponse { audioContent: Buffer; } export class TTSService { private readonly apiKey: string; private readonly apiUrl: string; private readonly outputDir: string = path.join(__dirname, '../../tmp/tts'); constructor() { this.apiKey = process.env.ELEVENLABS_API_KEY || ''; this.apiUrl = 'https://api.elevenlabs.io/v1/text-to-speech'; if (!this.apiKey) { throw new Error('ELEVENLABS_API_KEY environment variable is not set'); } // Ensure output directory exists fs.mkdirSync(this.outputDir, { recursive: true }); } async generateSpeech(options: TTSOptions): Promise { try { const voiceId = options.voice_id || 'pNInz6obpgDQGcFmaJgB'; // Default ElevenLabs voice const response = await axios.post( `${this.apiUrl}/${voiceId}`, { text: options.text, model_id: options.model_id || 'eleven_multilingual_v2', voice_settings: { stability: options.stability || 0.5, similarity_boost: options.similarity_boost || 0.75 } }, { headers: { 'xi-api-key': this.apiKey, 'Content-Type': 'application/json', 'Accept': 'audio/mpeg' }, responseType: 'arraybuffer' } ); const audioBuffer = response.data; const outputFileName = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}.mp3`; const outputPath = path.join(this.outputDir, outputFileName); await writeFile(outputPath, Buffer.from(audioBuffer)); // Calculate approximate duration (assuming average speaking rate) const wordCount = options.text.split(/\s+/).length; const approximateDuration = (wordCount / 150) * 60; // Assuming 150 words per minute return { audioContent: Buffer.from(audioBuffer) }; } catch (error) { console.error('Error generating speech:', error); throw new Error('Failed to generate speech'); } } async cleanup(filePath: string): Promise { try { await fs.promises.unlink(filePath); } catch (error) { console.error('Error cleaning up TTS file:', error); } } } export const ttsService = new TTSService();