use_elevenlabs = true; require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-twp-elevenlabs-api.php'; $this->elevenlabs_api = new TWP_ElevenLabs_API(); } } /** * Get cache key for text */ private function get_cache_key($text) { $voice_id = get_option('twp_elevenlabs_voice_id'); $model_id = get_option('twp_elevenlabs_model_id', 'eleven_multilingual_v2'); return 'twp_tts_' . md5($text . $voice_id . $model_id); } /** * Get cached audio URL if exists */ private function get_cached_audio($text) { $cache_key = $this->get_cache_key($text); $cached_data = get_transient($cache_key); if ($cached_data !== false) { // Verify the file still exists if (file_exists($cached_data['file_path'])) { error_log("TWP TTS: Using cached audio for text: " . substr($text, 0, 50) . "..."); return $cached_data; } else { // File was deleted, remove from cache delete_transient($cache_key); } } return false; } /** * Save audio to cache */ private function cache_audio($text, $audio_data) { $cache_key = $this->get_cache_key($text); // Cache for 30 days set_transient($cache_key, $audio_data, 30 * DAY_IN_SECONDS); } /** * Add TTS to TwiML Response * * @param \Twilio\TwiML\VoiceResponse $twiml The TwiML response object * @param string $text The text to speak * @param array $options Options for voice settings (used for Twilio fallback) * @return bool Success status */ public function add_tts_to_twiml($twiml, $text, $options = []) { // Default Twilio voice options $default_options = [ 'voice' => 'alice', 'language' => 'en-US' ]; $options = array_merge($default_options, $options); if ($this->use_elevenlabs) { // First check cache $cached_audio = $this->get_cached_audio($text); if ($cached_audio !== false) { $twiml->play($cached_audio['file_url']); return true; } // Not in cache, generate new audio $audio_result = $this->elevenlabs_api->text_to_speech($text); if ($audio_result && isset($audio_result['success']) && $audio_result['success']) { // Cache the result $this->cache_audio($text, [ 'file_url' => $audio_result['file_url'], 'file_path' => $audio_result['file_path'] ]); // Use the generated audio file $twiml->play($audio_result['file_url']); error_log("TWP TTS: Generated new ElevenLabs audio for text: " . substr($text, 0, 50) . "..."); return true; } else { // Log the failure and fall back to Twilio error_log("TWP TTS: ElevenLabs failed, falling back to Twilio. Error: " . (isset($audio_result['error']) ? $audio_result['error'] : 'Unknown error')); } } // Fall back to Twilio's built-in TTS $twiml->say($text, $options); error_log("TWP TTS: Using Twilio voice for text: " . substr($text, 0, 50) . "..."); return true; } /** * Generate TTS audio file (for pre-generation) * * @param string $text The text to convert * @return array|false Array with file_url on success, false on failure */ public function generate_tts_audio($text) { if (!$this->use_elevenlabs) { return false; } // First check cache $cached_audio = $this->get_cached_audio($text); if ($cached_audio !== false) { return [ 'success' => true, 'file_url' => $cached_audio['file_url'], 'file_path' => $cached_audio['file_path'], 'cached' => true ]; } // Not in cache, generate new audio $result = $this->elevenlabs_api->text_to_speech($text); if ($result && isset($result['success']) && $result['success']) { // Cache the result $this->cache_audio($text, [ 'file_url' => $result['file_url'], 'file_path' => $result['file_path'] ]); return [ 'success' => true, 'file_url' => $result['file_url'], 'file_path' => $result['file_path'], 'cached' => false ]; } return false; } /** * Check if ElevenLabs is configured and available * * @return bool */ public function is_elevenlabs_available() { return $this->use_elevenlabs; } /** * Get configured voice info * * @return array */ public function get_voice_info() { if ($this->use_elevenlabs) { return [ 'provider' => 'elevenlabs', 'voice_id' => get_option('twp_elevenlabs_voice_id'), 'model_id' => get_option('twp_elevenlabs_model_id', 'eleven_multilingual_v2') ]; } return [ 'provider' => 'twilio', 'voice' => 'alice', 'language' => 'en-US' ]; } /** * Clean up old TTS files (maintenance) */ public function cleanup_old_files($hours = 24) { $upload_dir = wp_upload_dir(); $path = $upload_dir['path']; // Only clean up TTS files older than specified hours $expire_time = time() - ($hours * 3600); $files = glob($path . '/tts_*.mp3'); if ($files) { foreach ($files as $file) { if (filemtime($file) < $expire_time) { unlink($file); error_log("TWP TTS: Cleaned up old file: " . basename($file)); } } } } }