api_key = get_option('twp_elevenlabs_api_key'); $this->voice_id = get_option('twp_elevenlabs_voice_id'); $this->model_id = get_option('twp_elevenlabs_model_id', 'eleven_multilingual_v2'); } /** * Convert text to speech */ public function text_to_speech($text, $voice_id = null) { // Handle both string voice_id and options array if (is_array($voice_id)) { $options = $voice_id; $voice_id = isset($options['voice_id']) ? $options['voice_id'] : null; } if (!$voice_id) { $voice_id = $this->voice_id; } $url = $this->api_base . '/text-to-speech/' . $voice_id; $data = array( 'text' => $text, 'model_id' => $this->model_id, 'voice_settings' => array( 'stability' => 0.5, 'similarity_boost' => 0.5 ) ); $response = $this->make_request('POST', $url, $data); if ($response['success']) { // Save audio file $upload_dir = wp_upload_dir(); $filename = 'tts_' . uniqid() . '.mp3'; $file_path = $upload_dir['path'] . '/' . $filename; $file_url = $upload_dir['url'] . '/' . $filename; file_put_contents($file_path, $response['data']); return array( 'success' => true, 'file_path' => $file_path, 'file_url' => $file_url ); } return $response; } /** * Get available voices */ public function get_voices() { $url = $this->api_base . '/voices'; $response = $this->make_request('GET', $url); if ($response['success'] && isset($response['data']['voices'])) { // Cache voices for 1 hour to reduce API calls set_transient('twp_elevenlabs_voices', $response['data']['voices'], HOUR_IN_SECONDS); } return $response; } /** * Get cached voices or fetch from API */ public function get_cached_voices() { $cached_voices = get_transient('twp_elevenlabs_voices'); if ($cached_voices !== false) { return array( 'success' => true, 'data' => array('voices' => $cached_voices) ); } return $this->get_voices(); } /** * Get voice details */ public function get_voice($voice_id) { $url = $this->api_base . '/voices/' . $voice_id; return $this->make_request('GET', $url); } /** * Get user subscription info */ public function get_subscription_info() { $url = $this->api_base . '/user/subscription'; return $this->make_request('GET', $url); } /** * Get available models */ public function get_models() { $url = $this->api_base . '/models'; $response = $this->make_request('GET', $url); if ($response['success'] && isset($response['data'])) { // Filter models that support text-to-speech $tts_models = array(); foreach ($response['data'] as $model) { if (isset($model['can_do_text_to_speech']) && $model['can_do_text_to_speech']) { $tts_models[] = $model; } } // Cache models for 1 hour set_transient('twp_elevenlabs_models', $tts_models, HOUR_IN_SECONDS); return array( 'success' => true, 'data' => $tts_models ); } return $response; } /** * Get cached models or fetch from API */ public function get_cached_models() { $cached_models = get_transient('twp_elevenlabs_models'); if ($cached_models !== false) { return array( 'success' => true, 'data' => $cached_models ); } return $this->get_models(); } /** * Generate speech for IVR menu */ public function generate_ivr_prompt($text, $options = array()) { $default_options = array( 'voice_id' => $this->voice_id, 'stability' => 0.75, 'similarity_boost' => 0.75, 'style' => 0, 'use_speaker_boost' => true ); $options = wp_parse_args($options, $default_options); $url = $this->api_base . '/text-to-speech/' . $options['voice_id']; $data = array( 'text' => $text, 'model_id' => $this->model_id, 'voice_settings' => array( 'stability' => $options['stability'], 'similarity_boost' => $options['similarity_boost'], 'style' => $options['style'], 'use_speaker_boost' => $options['use_speaker_boost'] ) ); return $this->make_request('POST', $url, $data); } /** * Generate speech for queue messages */ public function generate_queue_messages($messages) { $generated_files = array(); foreach ($messages as $key => $message) { $result = $this->text_to_speech($message); if ($result['success']) { $generated_files[$key] = $result['file_url']; } } return $generated_files; } /** * Stream text to speech (for real-time applications) */ public function stream_text_to_speech($text, $voice_id = null) { if (!$voice_id) { $voice_id = $this->voice_id; } $url = $this->api_base . '/text-to-speech/' . $voice_id . '/stream'; $data = array( 'text' => $text, 'model_id' => $this->model_id, 'voice_settings' => array( 'stability' => 0.5, 'similarity_boost' => 0.5 ), 'optimize_streaming_latency' => 3 ); return $this->make_request('POST', $url, $data, true); } /** * Make API request */ private function make_request($method, $url, $data = array(), $stream = false) { $args = array( 'method' => $method, 'headers' => array( 'xi-api-key' => $this->api_key, 'Content-Type' => 'application/json', 'Accept' => $stream ? 'audio/mpeg' : 'application/json' ), 'timeout' => 60 ); if ($method === 'POST' && !empty($data)) { $args['body'] = json_encode($data); } if ($method === 'GET') { $response = wp_remote_get($url, $args); } else { $response = wp_remote_post($url, $args); } if (is_wp_error($response)) { return array( 'success' => false, 'error' => $response->get_error_message() ); } $status_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($status_code >= 200 && $status_code < 300) { if ($stream || strpos(wp_remote_retrieve_header($response, 'content-type'), 'audio') !== false) { // Return raw audio data return array( 'success' => true, 'data' => $body ); } else { $decoded = json_decode($body, true); return array( 'success' => true, 'data' => $decoded ); } } else { $decoded = json_decode($body, true); return array( 'success' => false, 'error' => isset($decoded['detail']) ? $decoded['detail'] : 'API request failed', 'code' => $status_code ); } } /** * Cache generated audio */ public function cache_audio($text, $audio_data) { $cache_key = 'twp_tts_' . md5($text . $this->voice_id); set_transient($cache_key, $audio_data, DAY_IN_SECONDS * 7); return $cache_key; } /** * Get cached audio */ public function get_cached_audio($text) { $cache_key = 'twp_tts_' . md5($text . $this->voice_id); return get_transient($cache_key); } }