elevenlabs_field-1.0.0-beta7/src/ElevenLabsGenerateService.php
src/ElevenLabsGenerateService.php
<?php namespace Drupal\elevenlabs_field; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Utility\Token; use Drupal\file\FileRepositoryInterface; /** * Takes care of the Generating files from ElevenLabs. */ class ElevenLabsGenerateService { /** * The file system interface. */ protected FileSystemInterface $fileSystem; /** * The api interface. */ protected ElevenLabsApiService $api; /** * The entity type manager. */ protected EntityTypeManagerInterface $entityType; /** * The file repository. */ protected FileRepositoryInterface $fileRepo; /** * The token system. */ protected Token $token; /** * The models. */ protected array $models = []; /** * Construtor of ElevenLabs Generator Service. * * @param \Drupal\Core\File\FileSystemInterface $fileSystem * The file system interface. * @param \Drupal\elevenlabs_field\ElevenLabsApiService $api * The ElevenLabs API interface. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityType * The Entity Type manager interface. * @param \Drupal\file\FileRepositoryInterface $fileRepo * The file repository. * @param \Drupal\Core\Utility\Token $token * The token service. */ public function __construct(FileSystemInterface $fileSystem, ElevenLabsApiService $api, EntityTypeManagerInterface $entityType, FileRepositoryInterface $fileRepo, Token $token) { $this->fileSystem = $fileSystem; $this->api = $api; $this->entityType = $entityType; $this->fileRepo = $fileRepo; $this->models = $this->api->getModels(); $this->token = $token; } /** * Generate files. * * @param string $text * The text to create for. * @param string $speaker * The speaker to create for. * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition * The field definition. * @param string $model * The model to create with. * @param array $options * The extra options. * * @return array * An array of file and history id. */ public function generateFile($text, $speaker, FieldDefinitionInterface $fieldDefinition, $model, $options = []) { $return = []; $filePath = $this->getFilePath($fieldDefinition); $audioData = $this->api->textToSpeech($text, $speaker, $model, $options); if (is_string($audioData)) { // Remove old data if exists. $file = $this->generateAudio($audioData, $filePath); // Elevenlabs is not consistent with writes. sleep(1); $historyId = $this->findHistoryId($text, $speaker); if ($historyId && $file) { $return = [ 'file' => $file, 'history_item_id' => $historyId, ]; } } return $return; } /** * Gets the file path. * * @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition * The field definition interface. * * @return string * The path. */ public function getFilePath(FieldDefinitionInterface $fieldDefinition) { $settings = $fieldDefinition->getSettings(); $path = $settings['uri_scheme'] ?? 'public'; $path .= '://' . rtrim($this->token->replace($settings['file_directory']), '/'); $path .= '/' . $this->token->replace($settings['file_name'] ?? 'elevenlabs') . '.mp3'; return $path; } /** * Get the wanted model. * * @param string $modelName * The model or auto. * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * * @return string * The model. */ public function validateModel($modelName, ContentEntityInterface $entity) { // Only change if model is auto. if ($modelName == 'auto') { $modelName = ElevenLabsApiService::$defaultModel; $langCode = $entity->get('langcode')->value ?? NULL; if ($langCode) { foreach ($this->models as $model) { if (array_search($langCode, array_column($model['languages'], 'language_id'), TRUE)) { return $model['model_id']; } } } } return $modelName; } /** * Remove old file. * * @param int $id * The file to remove. */ public function removeFile($id) { if ($id) { $file = $this->entityType->getStorage('file')->load($id); $file ? $file->delete() : NULL; } } /** * Generate Audio file. * * @param string $audioData * Binary. * @param string $filePath * Path to store. * * @return \Drupal\file\Entity\File * A file entity. */ private function generateAudio($audioData, $filePath) { $dir = substr($filePath, 0, -(strlen(basename($filePath)))); $this->fileSystem->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); $file = $this->fileRepo->writeData($audioData, $filePath, FileSystemInterface::EXISTS_RENAME); return $file; } /** * Find the history Id. * * @param string $text * The text to search for. * @param string $speaker * The speaker to search for. * * @return string * The history item id. */ private function findHistoryId($text, $speaker) { $history = $this->api->getHistoryListing(); if (is_array($history)) { foreach ($history['history'] as $historyItem) { if ($historyItem['text'] == $text && $historyItem['voice_id'] == $speaker) { return $historyItem['history_item_id']; } } } } }