Files
twilio-wp-plugin/includes/class-twp-elevenlabs-api.php
2025-08-11 20:31:48 -07:00

302 lines
8.8 KiB
PHP

<?php
/**
* Eleven Labs API integration class
*/
class TWP_ElevenLabs_API {
private $api_key;
private $voice_id;
private $model_id;
private $api_base = 'https://api.elevenlabs.io/v1';
/**
* Constructor
*/
public function __construct() {
$this->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);
}
}