speech_elevenlabs.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. /**
  3. * ai_elevenlabs class
  4. *
  5. */
  6. class speech_elevenlabs implements speech_interface {
  7. private $voice;
  8. private $path;
  9. private $message;
  10. private $format;
  11. private $filename;
  12. private $languages;
  13. private $api_key;
  14. private $model;
  15. public function __construct($settings) {
  16. $this->voice = "";
  17. $this->path = "";
  18. $this->message = "";
  19. $this->format = "mp3";
  20. $this->filename = "";
  21. //build the setting object and get the recording path
  22. $this->api_key = $settings->get('speech', 'api_key');
  23. }
  24. public function set_filename(string $audio_filename) {
  25. $this->filename = $audio_filename;
  26. }
  27. public function set_format(string $audio_format) {
  28. $this->format = $audio_format;
  29. }
  30. public function set_message(string $audio_message) {
  31. $this->message = $audio_message;
  32. }
  33. public function set_path(string $audio_path) {
  34. $this->path = $audio_path;
  35. }
  36. public function set_voice(string $audio_voice) {
  37. $this->voice = $audio_voice;
  38. }
  39. public function speech(): bool {
  40. //get the model automatically
  41. $model_id = $this->get_model();
  42. //if model is version 1 replace it with version 2
  43. if ($model_id == 'eleven_multilingual_v1') {
  44. $model_id = 'eleven_multilingual_v2';
  45. }
  46. // set the request URL
  47. $url = 'https://api.elevenlabs.io/v1/text-to-speech/' . $this->voice;
  48. // set the request headers
  49. $headers[] = 'Content-Type: application/json';
  50. $headers[] = 'xi-api-key: '.$this->api_key;
  51. // set the http data
  52. $data['model_id'] = $model_id;
  53. $data['text'] = $this->message;
  54. //$data['pronunciation_dictionary_locators'][0]['pronunciation_dictionary_id'];
  55. //$data['pronunciation_dictionary_locators'][0]['version_id'];
  56. $data['voice_settings']['similarity_boost'] = 1;
  57. $data['voice_settings']['stability'] = 1;
  58. $data['voice_settings']['style'] = 0;
  59. $data['voice_settings']['use_speaker_boost'] = 'true';
  60. // initialize curl handle
  61. $ch = curl_init($url);
  62. // set the curl options
  63. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  64. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  65. curl_setopt($ch, CURLOPT_POST, true);
  66. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  67. // run the curl request and get the response
  68. $response = curl_exec($ch);
  69. // get the errors
  70. $error = curl_error($ch);
  71. // get the http code
  72. $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  73. // close the handle
  74. curl_close($ch);
  75. // show the result when there is an error
  76. if ($http_code != 200) {
  77. echo "error ".$error."\n";
  78. echo "http_code ".$http_code."\n";
  79. if (strlen($response) < 500) {
  80. view_array(json_decode($response, true));
  81. }
  82. exit;
  83. }
  84. // save the audio file
  85. if ($http_code == 200) {
  86. //get the file and path details
  87. $path_array = pathinfo($this->filename);
  88. //save the file as an mp3
  89. file_put_contents($this->path.'/'.$path_array['filename'].'.mp3', $response);
  90. //find the location of sox
  91. $command = 'which sox';
  92. $sox = system($command);
  93. //use sox to convert mp3 to wav
  94. if (file_exists($this->path.'/'.$path_array['filename'].'.mp3')) {
  95. $command = $sox . " '".$this->path."/".$path_array['filename'].".mp3' -r 44100 -b 16 '".$this->path."/".$path_array['filename'].".wav'";
  96. system($command);
  97. }
  98. //delete the extra file
  99. if (file_exists($this->path.'/'.$path_array['filename'].'.wav')) {
  100. unlink($this->path.'/'.$path_array['filename'].'.mp3');
  101. }
  102. return true;
  103. }
  104. return false;
  105. //$curl = new curl('https://api.elevenlabs.io/v1/text-to-speech/' . $this->voice);
  106. //$response = $curl->set_headers($headers)->post(json_encode($data));
  107. //$error = $curl->get_error();
  108. //$http_code = $curl->get_http_code();
  109. //if ($curl->get_http_code() == 200) {
  110. //save the audio
  111. //if ($http_code == 200) {
  112. // file_put_contents($this->path . '/' . $this->filename, $response);
  113. // return true;
  114. //}
  115. //return false;
  116. }
  117. public function is_language_enabled(): bool {
  118. return false;
  119. }
  120. public function is_model_enabled(): bool {
  121. return false;
  122. }
  123. public function get_languages(): array {
  124. return ['en' => 'English'];
  125. }
  126. public function get_voices(): array {
  127. $return_value = [];
  128. $url = 'https://api.elevenlabs.io/v1/voices';
  129. $headers = [
  130. 'Content-Type: application/json',
  131. "xi-api-key: $this->api_key",
  132. ];
  133. $curl = curl_init();
  134. curl_setopt_array($curl, [
  135. CURLOPT_URL => $url,
  136. CURLOPT_RETURNTRANSFER => true,
  137. CURLOPT_ENCODING => "",
  138. CURLOPT_MAXREDIRS => 10,
  139. CURLOPT_TIMEOUT => 30,
  140. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  141. CURLOPT_CUSTOMREQUEST => "GET",
  142. CURLOPT_CUSTOMREQUEST => "GET",
  143. CURLOPT_HTTPHEADER => $headers,
  144. ]);
  145. $response = curl_exec($curl);
  146. $error = curl_error($curl);
  147. curl_close($curl);
  148. if (!empty($response)) {
  149. $json_array = json_decode($response, true);
  150. foreach($json_array['voices'] as $row) {
  151. $voice_id = $row['voice_id'];
  152. $name = $row['name'];
  153. $gender = $row['labels']['gender'] ?? '';
  154. $accent = $row['labels']['accent'] ?? '';
  155. $use_case = $row['labels']['use case'] ?? '';
  156. $recommended_model = $row['high_quality_base_model_ids'][0] ?? '';
  157. $return_value[$voice_id] = "$name ($gender, $accent";
  158. if (!empty($use_case)) {
  159. $return_value[$voice_id] .= ", " . $use_case;
  160. }
  161. $return_value[$voice_id] .= ")";
  162. if (!empty($recommended_model)) {
  163. $return_value[$voice_id] .= " - $recommended_model";
  164. }
  165. }
  166. }
  167. return $return_value;
  168. }
  169. public function set_language(string $audio_language) {
  170. $this->languages = $audio_language;
  171. }
  172. public function set_model(string $model): void {
  173. if (array_key_exists($model, $this->get_models())) {
  174. $this->model = $model;
  175. }
  176. }
  177. public function get_model() {
  178. //if the voice is not set return the default model
  179. if (empty($this->voice)) {
  180. return 'eleven_monolingual_v1';
  181. }
  182. //get the voices and automatically find the model
  183. $url = 'https://api.elevenlabs.io/v1/voices';
  184. $headers = [
  185. 'Content-Type: application/json',
  186. "xi-api-key: $this->api_key",
  187. ];
  188. $curl = curl_init();
  189. curl_setopt_array($curl, [
  190. CURLOPT_URL => $url,
  191. CURLOPT_RETURNTRANSFER => true,
  192. CURLOPT_ENCODING => "",
  193. CURLOPT_MAXREDIRS => 10,
  194. CURLOPT_TIMEOUT => 30,
  195. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  196. CURLOPT_CUSTOMREQUEST => "GET",
  197. CURLOPT_HTTPHEADER => $headers,
  198. ]);
  199. $response = curl_exec($curl);
  200. $error = curl_error($curl);
  201. curl_close($curl);
  202. if (!empty($response)) {
  203. $json_array = json_decode($response, true);
  204. foreach($json_array['voices'] as $row) {
  205. if ($this->voice == $row['voice_id'] && !empty($row['high_quality_base_model_ids'][0])) {
  206. return $row['high_quality_base_model_ids'][0];
  207. }
  208. }
  209. return 'eleven_monolingual_v1';
  210. }
  211. }
  212. public function get_models(): array {
  213. return [
  214. 'eleven_monolingual_v1' => 'Default',
  215. 'eleven_turbo_v1' => 'Eleven Turbo v1',
  216. 'eleven_turbo_v2' => 'Eleven Turbo v2',
  217. 'eleven_multilingual_v1' => 'Eleven Multilingual v1',
  218. 'eleven_multilingual_v2' => 'Eleven Multilingual v2',
  219. ];
  220. }
  221. }
  222. ?>